Open stajnert opened 11 years ago
@panslaw show your CompanyImage class, I think you're missing the setParent method
Below you can find my CompanyImage. I add setParent method and (you're right) relation was saved. The file is not save on disk because I don't run upload method. On section How to handle File Uploads with Doctrine I can run this method after valid form. These methods: getAbsolutePath(), getWebPath(), getUploadRootDir(), getUploadDir(), upload() are needed with your bundle?
<?php
namespace Goat\CompanyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Avocode\FormExtensionsBundle\Form\Model\UploadCollectionFileInterface;
/**
* CompanyImage
*/
class CompanyImage implements UploadCollectionFileInterface
{
/**
* @var integer
*/
private $id;
/**
* @var boolean
*/
private $active;
/**
* @var string
*/
protected $file;
/**
* @var \DateTime
*/
private $created;
/**
* @var \DateTime
*/
private $updated;
/**
* @var \Goat\CompanyBundle\Entity\Company
*/
private $company;
protected $path;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set active
*
* @param boolean $active
* @return CompanyImage
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Set file
*
* @param string $file
* @return CompanyImage
*/
/* public function setFile($file)
{
$this->file = $file;
return $this;
} */
/**
* Get file
*
* @return string
*/
/* public function getFile()
{
return $this->file;
} */
/**
* Set created
*
* @param \DateTime $created
* @return CompanyImage
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* @param \DateTime $updated
* @return CompanyImage
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* @return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set company
*
* @param \Goat\CompanyBundle\Entity\Company $company
* @return CompanyImage
*/
public function setCompany(\Goat\CompanyBundle\Entity\Company $company)
{
$this->company = $company;
return $this;
}
/**
* Get company
*
* @return \Goat\CompanyBundle\Entity\Company
*/
public function getCompany()
{
return $this->company;
}
// see note below
public function getFileWebPath()
{
return $this->getWebPath();
}
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/company/images';
}
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
$filename = sha1(uniqid(mt_rand(), true)) . '.' . $this->getFile()->guessExtension();
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move(
$this->getUploadRootDir(), $filename
);
// set the path property to the filename where you've saved the file
$this->file = $filename;
// clean up the file property as you won't need it anymore
$this->path = null;
}
public function getFile()
{
// inject file into property (if uploaded)
if ($this->getAbsolutePath()) {
return new \Symfony\Component\HttpFoundation\File\File(
$this->getAbsolutePath()
);
}
return null;
}
public function getSize()
{
return $this->getFile()->getFileInfo()->getSize();
}
public function getPreview()
{
return (preg_match('/image\/.*/i', $this->getFile()->getMimeType()));
}
public function setFile(\Symfony\Component\HttpFoundation\File\File $file)
{
$this->file = $file;
return $this;
}
public function setParent($parent)
{
$this->setCompany($parent);
}
/**
* @var string
*/
private $name;
/**
* Set name
*
* @param string $name
* @return CompanyImage
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
}
@panslaw the way you handle file uploads is totally up to you:
Just remember that when the eventListener "catches" new uploaded files, it does this
<?php
$file = new $this->dataClass();
if (!$file instanceof UploadCollectionFileInterface) {
throw new UnexpectedTypeException($file, '\Avocode\FormExtensionsBundle\Form\Model\UploadCollectionFileInterface');
}
$file->setFile($upload);
$file->setParent($data);
So.. when setFile is called you must trigger the upload method (move the file, save the path) and when setParent is called you must save the relation between the parent that holds the collection (eg. Album
) and the child (eg. AlbumImage
).
I decided to use VichUploaderBundle and yes, file is move to correctly directory and save on database full path to file (is it correct behavior?) - one step close :) but after refresh page I can't see no one added files. Which bundle is responsible for display uploaded images and what else I should configure?
VichUploaderBundle is only responsible for UPLOAD and injecting a file into property. So every time you do $object = $doctrine->getManager()->getRepository('AcmeDemoBundle:MyTestFile')->find($id)
then $object->getFile() will return Symfony\Component\HttpFoundation\File\File
(which extends PHP's SplFileInfo)
Displaying the already added files is CollectionUpload job.
If you have files in the database saved properly and you get no errors when displaying the form, then maybe check symfony2 logs for errors?
I checked logs but there is no errors. On logs side everything looks fine. I have no idea. Maybe it's problem with file path? Should I have on database full file path or only path starts from /web directory (like /uploads/company/image/file.jpg)?
No. Your path should contain only the file name (if you're useing Vich).
look here for example vich configuration
this config defines that all gallery_image
should be placed into %kernel.root_dir%/../web/gallery/image
directory. So the PATH property only holds the file name and the application knows where to look for gallery_image
s thanks to this (vich uploader bundle configuration) mapping
I have the same configuration, but Vich Bundle saves full path to image in database, not only file name. It's not path problem, when I left in table only file name and remove rest of path file is not listed.
Wow, something different! Before I tried edit object - it doesn't works. Now I tried add new object and I see that collection upload add another files below buttons but now when I submit form I've got error:
Warning: Invalid argument supplied for foreach() in C:\wamp\www\koziolki\vendor\avocode\form-extensions-bundle\Avocode\FormExtensionsBundle\Form\EventListener\CollectionUploadSubscriber.php line 122
On line 122 the event listener is looping through ArrayCollection of items and removeing those, whose primary key has not been submitted.
Please show your \Acme\CompanyBundle\Form\Type\CompanyImageAdmin\EditType
OR generator.yml
file used to generate that form type
My CompanyBundle\Form\Type\CompanyImageAdmin\EditType is empty - is generated by generator
namespace Goat\CompanyBundle\Form\Type\CompanyImageAdmin;
use Admingenerated\GoatCompanyBundle\Form\BaseCompanyImageAdminType\EditType as BaseEditType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class EditType extends BaseEditType
{
}
and my CompanyAdmin-generator.yml
generator: admingenerator.generator.doctrine
params:
model: Goat\CompanyBundle\Entity\Company
namespace_prefix: Goat
entity_manager: ~
concurrency_lock: ~
bundle_name: CompanyBundle
pk_requirement: ~
embed_types:
- "CompanyImageAdmin-generator.yml"
fields:
images:
label: Images
dbType: collection
formType: collection_upload
addFormOptions:
nameable: false
editable: [ file ]
#
### you can create your own form type
# type: \Acme\DemoBundle\Form\MyFormType
#
### or use admin:generate-admin command and use the admingenerated form type
type: \Goat\CompanyBundle\Form\Type\CompanyImageAdmin\EditType
#
maxNumberOfFiles: 5
maxFileSize: 500000
minFileSize: 1000
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
loadImageFileTypes: /^image\/(gif|jpe?g|png)$/i
loadImageMaxFileSize: 250000
previewMaxWidth: 100
previewMaxHeight: 100
previewAsCanvas: true
prependFiles: false
allow_add: true
allow_delete: true
error_bubbling: false
options:
data_class: Goat\CompanyBundle\Entity\CompanyImage
object_actions:
delete: ~
batch_actions:
delete: ~
builders:
list:
params:
title: List for CompanyBundle
display: [id, active, name, postcode, street, created]
actions:
new: ~
object_actions:
edit: ~
delete: ~
filters:
params:
display: [id, name, slug, postcode, street, www]
new:
params:
title: New object for CompanyBundle
display: [name, slug, postcode, street, www, images]
actions:
save: ~
list: ~
edit:
params:
title: "You're editing the object \"%object%\"|{ %object%: Company.name }|"
display: ~
tabs:
"General information":
"Basic": [active, city, district, name, logo, description, postcode, street, www, images]
"Images":
"Images": []
"Subtrades":
"Subtrades": []
actions:
save: ~
list: ~
show:
params:
title: "You're viewing the object \"%object%\"|{ %object%: Company.name }|"
display: ~
actions:
list: ~
new: ~
actions:
params:
object_actions:
delete: ~
batch_actions:
delete: ~
and CompanyImageAdmin-generator.yml
generator: admingenerator.generator.doctrine
params:
model: Goat\CompanyBundle\Entity\CompanyImage
namespace_prefix: Goat
entity_manager: ~
concurrency_lock: ~
bundle_name: CompanyBundle
pk_requirement: ~
fields: ~
object_actions:
delete: ~
batch_actions:
delete: ~
builders:
list:
params:
title: List for CompanyBundle
display: ~
actions:
new: ~
object_actions:
edit: ~
delete: ~
filters:
params:
display: ~
new:
params:
title: New object for CompanyBundle
display: ~
actions:
save: ~
list: ~
edit:
params:
title: "You're editing the object \"%object%\"|{ %object%: YourModel.title }|"
display: ~
actions:
save: ~
list: ~
show:
params:
title: "You're viewing the object \"%object%\"|{ %object%: YourModel.title }|"
display: ~
actions:
list: ~
new: ~
actions:
params:
object_actions:
delete: ~
batch_actions:
delete: ~
CompanyImageAdmin needs only edit builder (to generate the edit form type):
generator: admingenerator.generator.doctrine
params:
model: Goat\CompanyBundle\Entity\CompanyImage
namespace_prefix: Goat
bundle_name: CompanyBundle
builders:
edit:
params:
display: [ id ] # here add all fields that have to be edited
# including primary_key, nameable_field, sortable_field, but NOT file field
# eg. [ id, name, description ]
# we're useing it only to generate the form type
title: "" # no need for title in this builder
actions: [] # no need for actions in this builder
Also, remove file
from editable
option in CompanyAdmin entity:
editable: []
# this is only for additional metadata fields, like
# adding a "description" field
# primary_key, nameable_field, sortable_field and file should not be added in editable
File field is not editable. The widget allows you to remove an image (and related entity) and add another one, but does not allow changeing image/file for already existing image/file entity.
With changes I have error:
Key "id" in object (with ArrayAccess) of type "Symfony\Component\Form\FormView" does not exist in AvocodeFormExtensionsBundle:Form/CollectionUpload:template_download.html.twig at line 34
my php CompanyImageAdmin-generator.yml
generator: admingenerator.generator.doctrine
params:
model: Goat\CompanyBundle\Entity\CompanyImage
namespace_prefix: Goat
entity_manager: ~
concurrency_lock: ~
bundle_name: CompanyBundle
pk_requirement: ~
fields: ~
object_actions:
delete: ~
batch_actions:
delete: ~
builders:
edit:
params:
title: "edit"
display: [ id ]
actions: []
and php CompanyAdmin-generator.yml
generator: admingenerator.generator.doctrine
params:
model: Goat\CompanyBundle\Entity\Company
namespace_prefix: Goat
entity_manager: ~
concurrency_lock: ~
bundle_name: CompanyBundle
pk_requirement: ~
embed_types:
- "CompanyImageAdmin-generator.yml"
fields:
images:
label: Images
dbType: collection
formType: collection_upload
addFormOptions:
nameable: false
editable: []
#
### you can create your own form type
# type: \Acme\DemoBundle\Form\MyFormType
#
### or use admin:generate-admin command and use the admingenerated form type
type: \Goat\CompanyBundle\Form\Type\CompanyImageAdmin\EditType
#
maxNumberOfFiles: 5
maxFileSize: 500000
minFileSize: 1000
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
loadImageFileTypes: /^image\/(gif|jpe?g|png)$/i
loadImageMaxFileSize: 250000
previewMaxWidth: 100
previewMaxHeight: 100
previewAsCanvas: true
prependFiles: false
allow_add: true
allow_delete: true
error_bubbling: false
options:
data_class: Goat\CompanyBundle\Entity\CompanyImage
object_actions:
delete: ~
batch_actions:
delete: ~
builders:
list:
params:
title: List for CompanyBundle
display: [id, active, name, postcode, street, created]
actions:
new: ~
object_actions:
edit: ~
delete: ~
filters:
params:
display: [id, name, slug, postcode, street, www]
new:
params:
title: New object for CompanyBundle
display: [name, slug, postcode, street, www, images]
actions:
save: ~
list: ~
edit:
params:
title: "You're editing the object \"%object%\"|{ %object%: Company.name }|"
display: ~
tabs:
"General information":
"Basic": [active, city, district, name, logo, description, postcode, street, www, images]
"Images":
"Images": []
"Subtrades":
"Subtrades": []
actions:
save: ~
list: ~
show:
params:
title: "You're viewing the object \"%object%\"|{ %object%: Company.name }|"
display: ~
actions:
list: ~
new: ~
actions:
params:
object_actions:
delete: ~
batch_actions:
delete: ~
@panslaw This is weird as on this line of template_dowload.html.twig
the primary_key is not used (it's rendered a bit lower, on line 43. I'm sorry but I must miss something. I don't see where is the error. I'm sure the widget works becouse I've been fixing it 2 weeks ago and tested everything, so it must be something in your configuration, i just dont see it.
When I removed cache error with Key "id" in object (with ArrayAccess) is missing but I have previous one:
Warning: Invalid argument supplied for foreach() in C:\wamp\www\koziolki\vendor\avocode\form-extensions-bundle\Avocode\FormExtensionsBundle\Form\EventListener\CollectionUploadSubscriber.php line 122
Edit CollectionUploadSubscriber.php
on line 122 and check what is passed to foreach loop
I checked three things (onSubmit method):
1) var_dump($data);
object(Goat\CompanyBundle\Entity\Company)[4267]
private 'id' => null
private 'active' => null
private 'slug' => null
private 'name' => null
private 'logo' => null
private 'description' => null
private 'postcode' => null
private 'street' => null
private 'www' => null
private 'created' => null
private 'updated' => null
private 'emails' =>
object(Doctrine\Common\Collections\ArrayCollection)[4266]
private '_elements' =>
array (size=0)
empty
private 'faxes' =>
object(Doctrine\Common\Collections\ArrayCollection)[4265]
private '_elements' =>
array (size=0)
empty
private 'phones' =>
object(Doctrine\Common\Collections\ArrayCollection)[118]
private '_elements' =>
array (size=0)
empty
private 'city' => null
private 'district' => null
private 'subtrades' =>
object(Doctrine\Common\Collections\ArrayCollection)[3546]
private '_elements' =>
array (size=0)
empty
private 'path' => null
private 'images' => null
2) var_dump($getter);
string 'getImages' (length=9)
3) var_dump($data->$getter());
null
And if you want this is my Company.php
file from Entity directory
<?php
namespace Goat\CompanyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Company
*/
class Company
{
/**
* @var integer
*/
private $id;
/**
* @var boolean
*/
private $active;
/**
* @var string
*/
private $slug;
/**
* @var string
*/
private $name;
/**
* @Assert\File(maxSize="6000000")
*/
private $logo;
/**
* @var string
*/
private $description;
/**
* @var string
*/
private $postcode;
/**
* @var string
*/
private $street;
/**
* @var string
*/
private $www;
/**
* @var \DateTime
*/
private $created;
/**
* @var \DateTime
*/
private $updated;
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $emails;
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $faxes;
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $phones;
/**
* @var \Goat\CompanyBundle\Entity\City
*/
private $city;
/**
* @var \Goat\CompanyBundle\Entity\District
*/
private $district;
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $subtrades;
private $path;
/**
* Constructor
*/
public function __construct()
{
$this->emails = new \Doctrine\Common\Collections\ArrayCollection();
$this->faxes = new \Doctrine\Common\Collections\ArrayCollection();
$this->phones = new \Doctrine\Common\Collections\ArrayCollection();
$this->subtrades = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set active
*
* @param boolean $active
* @return Company
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Set slug
*
* @param string $slug
* @return Company
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* @return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set name
*
* @param string $name
* @return Company
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set logo
*
* @param string $logo
* @return Company
*/
public function setLogo(UploadedFile $logo = null)
{
$this->logo = $logo;
//return $this;
}
/**
* Get logo
*
* @return string
*/
public function getLogo()
{
return $this->logo;
}
/**
* Set description
*
* @param string $description
* @return Company
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set postcode
*
* @param string $postcode
* @return Company
*/
public function setPostcode($postcode)
{
$this->postcode = $postcode;
return $this;
}
/**
* Get postcode
*
* @return string
*/
public function getPostcode()
{
return $this->postcode;
}
/**
* Set street
*
* @param string $street
* @return Company
*/
public function setStreet($street)
{
$this->street = $street;
return $this;
}
/**
* Get street
*
* @return string
*/
public function getStreet()
{
return $this->street;
}
/**
* Set www
*
* @param string $www
* @return Company
*/
public function setWww($www)
{
$this->www = $www;
return $this;
}
/**
* Get www
*
* @return string
*/
public function getWww()
{
return $this->www;
}
/**
* Set created
*
* @param \DateTime $created
* @return Company
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* @param \DateTime $updated
* @return Company
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* @return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Add emails
*
* @param \Goat\CompanyBundle\Entity\CompanyEmail $emails
* @return Company
*/
public function addEmail(\Goat\CompanyBundle\Entity\CompanyEmail $emails)
{
$this->emails[] = $emails;
return $this;
}
/**
* Remove emails
*
* @param \Goat\CompanyBundle\Entity\CompanyEmail $emails
*/
public function removeEmail(\Goat\CompanyBundle\Entity\CompanyEmail $emails)
{
$this->emails->removeElement($emails);
}
/**
* Get emails
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getEmails()
{
return $this->emails;
}
/**
* Add faxes
*
* @param \Goat\CompanyBundle\Entity\CompanyFax $faxes
* @return Company
*/
public function addFaxe(\Goat\CompanyBundle\Entity\CompanyFax $faxes)
{
$this->faxes[] = $faxes;
return $this;
}
/**
* Remove faxes
*
* @param \Goat\CompanyBundle\Entity\CompanyFax $faxes
*/
public function removeFaxe(\Goat\CompanyBundle\Entity\CompanyFax $faxes)
{
$this->faxes->removeElement($faxes);
}
/**
* Get faxes
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getFaxes()
{
return $this->faxes;
}
/**
* Add phones
*
* @param \Goat\CompanyBundle\Entity\CompanyPhone $phones
* @return Company
*/
public function addPhone(\Goat\CompanyBundle\Entity\CompanyPhone $phones)
{
$this->phones[] = $phones;
return $this;
}
/**
* Remove phones
*
* @param \Goat\CompanyBundle\Entity\CompanyPhone $phones
*/
public function removePhone(\Goat\CompanyBundle\Entity\CompanyPhone $phones)
{
$this->phones->removeElement($phones);
}
/**
* Get phones
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getPhones()
{
return $this->phones;
}
/**
* Set city
*
* @param \Goat\CompanyBundle\Entity\City $city
* @return Company
*/
public function setCity(\Goat\CompanyBundle\Entity\City $city = null)
{
$this->city = $city;
return $this;
}
/**
* Get city
*
* @return \Goat\CompanyBundle\Entity\City
*/
public function getCity()
{
return $this->city;
}
/**
* Set district
*
* @param \Goat\CompanyBundle\Entity\District $district
* @return Company
*/
public function setDistrict(\Goat\CompanyBundle\Entity\District $district = null)
{
$this->district = $district;
return $this;
}
/**
* Get district
*
* @return \Goat\CompanyBundle\Entity\District
*/
public function getDistrict()
{
return $this->district;
}
/**
* Add subtrades
*
* @param \Goat\TradeBundle\Entity\Subtrade $subtrades
* @return Company
*/
public function addSubtrade(\Goat\TradeBundle\Entity\Subtrade $subtrades)
{
$this->subtrades[] = $subtrades;
return $this;
}
/**
* Remove subtrades
*
* @param \Goat\TradeBundle\Entity\Subtrade $subtrades
*/
public function removeSubtrade(\Goat\TradeBundle\Entity\Subtrade $subtrades)
{
$this->subtrades->removeElement($subtrades);
}
/**
* Get subtrades
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getSubtrades()
{
return $this->subtrades;
}
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $images;
/**
* Add images
*
* @param \Goat\CompanyBundle\Entity\CompanyImage $images
* @return Company
*/
public function addImages(\Goat\CompanyBundle\Entity\CompanyImage $images)
{
$this->images[] = $images;
return $this;
}
/**
* Remove images
*
* @param \Goat\CompanyBundle\Entity\CompanyImage $images
*/
public function removeImages(\Goat\CompanyBundle\Entity\CompanyImage $images)
{
$this->images->removeElement($images);
}
/**
* Get images
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getImages()
{
return $this->images;
}
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/company/logo';
}
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getLogo()) {
return;
}
$filename = sha1(uniqid(mt_rand(), true)) . '.' . $this->getLogo()->guessExtension();
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getLogo()->move(
$this->getUploadRootDir(), $filename
);
// set the path property to the filename where you've saved the file
$this->logo = $filename;
// clean up the file property as you won't need it anymore
$this->path = null;
}
}
You're missing this in the contructor:
<?php
public function __construct()
{
// ..
$this->images = new \Doctrine\Common\Collections\ArrayCollection();
}
Yes, I've notice this after write comment. I added this and now error is missing but I have two other things:
1) when I choose more than one file only one from these (the last one) is uploaded and save into database. Just one.
2) after refresh page I have edit screen and I don't see any images and I can't add new image - on log I've got error: emergency.EMERGENCY: Call to a member function getFileInfo() on a non-object {"type":1,"file":"\\src\\Goat\\CompanyBundle\\Entity\\CompanyImage.php","line":266} []
my CompanyImage.php
:
<?php
namespace Goat\CompanyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Avocode\FormExtensionsBundle\Form\Model\UploadCollectionFileInterface;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @Vich\Uploadable
*/
class CompanyImage implements UploadCollectionFileInterface
{
/**
* @var integer
*/
private $id;
/**
* @var boolean
*/
private $active;
/**
* @Vich\UploadableField(mapping="company_image", fileNameProperty="path")
*/
protected $file;
/**
* @var \DateTime
*/
private $created;
/**
* @var \DateTime
*/
private $updated;
/**
* @var \Goat\CompanyBundle\Entity\Company
*/
private $company;
protected $path;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set active
*
* @param boolean $active
* @return CompanyImage
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Set file
*
* @param string $file
* @return CompanyImage
*/
/* public function setFile($file)
{
$this->file = $file;
return $this;
} */
/**
* Get file
*
* @return string
*/
//public function getFile()
//{
//return $this->file;
//}
/**
* Set created
*
* @param \DateTime $created
* @return CompanyImage
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* @param \DateTime $updated
* @return CompanyImage
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* @return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set company
*
* @param \Goat\CompanyBundle\Entity\Company $company
* @return CompanyImage
*/
public function setCompany(\Goat\CompanyBundle\Entity\Company $company)
{
$this->company = $company;
return $this;
}
/**
* Get company
*
* @return \Goat\CompanyBundle\Entity\Company
*/
public function getCompany()
{
return $this->company;
}
/*
// see note below
public function getFileWebPath()
{
return $this->getWebPath();
}
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/company/images';
}
public function upload()
{
// the file property can be empty if the field is not required
//if (null === $this->getFile()) {
// return;
//}
$filename = sha1(uniqid(mt_rand(), true)) . '.' . $this->getFile()->guessExtension();
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move(
$this->getUploadRootDir(), $filename
);
// set the path property to the filename where you've saved the file
$this->file = $filename;
// clean up the file property as you won't need it anymore
$this->path = null;
}
public function getFile()
{
// inject file into property (if uploaded)
if ($this->getAbsolutePath()) {
return new \Symfony\Component\HttpFoundation\File\File(
$this->getAbsolutePath()
);
}
return null;
}
public function getSize()
{
return $this->getFile()->getFileInfo()->getSize();
}
public function setFile(\Symfony\Component\HttpFoundation\File\File $file)
{
$this->upload();
$this->file = $file;
return $this;
}
public function setParent($parent)
{
$this->setCompany($parent);
}
*/
public function setFile(\Symfony\Component\HttpFoundation\File\File $file) {
$this->file = $file;
return $this;
}
public function getFile() {
return $this->file;
}
public function getSize() {
return $this->file->getFileInfo()->getSize();
}
public function setParent($parent) {
$this->setCompany($parent);
}
public function getPreview() {
return (preg_match('/image\/.*/i', $this->file->getMimeType()));
}
/**
* @var string
*/
private $name;
/**
* Set name
*
* @param string $name
* @return CompanyImage
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
}
And which is the line 266 mentioned in the error?
return $this->file->getFileInfo()->getSize();
Do you have inject_on_load: true
in your vich configuration for that file mapping?
Yes, this is my configuration:
vich_uploader:
db_driver: orm
gaufrette: false
storage: vich_uploader.storage.file_system
mappings:
company_image:
uri_prefix: /company/images
upload_destination: %kernel.root_dir%/../web/uploads/company/images
namer: vich_uploader.namer_uniqid
inject_on_load: true
delete_on_remove: true
delete_on_update: true
Ok, I solved problem with this return $this->file->getFileInfo()->getSize();
error - I didn't have column path in database.
Still I can't add more than one file. When I try upload (for example) three images only the last one was uploaded and saved in database. After reload page (edit) I see one image and when I try (on edit) add another I've got error:
Neither the property "id" nor one of the methods "setId()", "__set()" or "__call()" exist and have public access in class "Goat\CompanyBundle\Entity\CompanyImage".
Do you have one full working example of this kind of relation? I don't know what I'm doing wrong.
The example code in documentation is used and working in one of my projects. I only changed namespaces to Acme
.
I have problem with relations one-to-many. I have two entities: company and related table company_images (with company_id column). Here is part of my company-generator.yml:
When I try submit form I have error
An exception occurred while executing 'INSERT INTO company_image (active, name, file, created, updated, company_id) VALUES (?, ?, ?, ?, ?, ?)' with params [null, "test.jpg", {}, "2013-08-09 10:07:54", "2013-08-09 10:07:54", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'company_id' cannot be null
How I should do this in right way?