Vich and gaufrette are not saving files in sonata admin - php

I'm trying to make an upload linked to an entity in Sonata Admin using Vich.
All the configuration is done but the file does not upload, and I cannot find the error.
The problem is that when y try to upload the file, every thing seem to work fine, Sonata persists the data in all the data base fields, and the file is uploaded to /tmp folder in teh sistem,also, sonata prints the tmp route in the patch field in database. But the file never gets to the folder setted in gaufrette and neither generates the unique name.
Here is the code:
The admin Class:
<?php
namespace DownloadFileAdminBundle\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
class DownloadFileAdmin extends Admin
{
const FILE_MAX_SIZE = 2 * 1024 * 1024; // 2 megas
/**
* #param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$fileOptions = array(
'label' => 'Archivo',
'required' => true,
'vich_file_object' => 'downloadfile',
'vich_file_property' => 'downloadFile',
'vich_allow_delete' => true,
'attr' => array(
'data-max-size' => self::FILE_MAX_SIZE,
'data-max-size-error' => 'El tamaño del archivo no puede ser mayor de 2 megas'
)
);
$formMapper
->add('slug', null, array('label' => 'Slug'))
->add('title', null, array('label' => 'Título'))
->add('description', null, array('label' => 'Descripción'))
->add('roles')
->add('path', 'DownloadFileAdminBundle\Form\Extension\VichFileObjectType', $fileOptions)
;
}
/**
* #param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('id')
->add('slug')
->add('title')
->add('description')
->add('path')
->add('roles')
->add('_action', null, array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
)
))
;
}
}
Here is the entity, with the not persistent fieln and the path field, witch is wher eI want tostore the file path:
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
* #Vich\UploadableField(mapping="download_file", fileNameProperty="path")
* #var File
*/
private $downloadFile;
/**
* #ORM\Column(type="string")
*/
protected $path;
public function getDownloadFile()
{
return $this->downloadFile;
}
/**
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $file
*
* #return File
*/
public function setDownloadFile(File $file = null)
{
$this->downloadFile = $file;
return $this;
}
/**
* #return mixed
*/
public function getPath()
{
return $this->path;
}
/**
* #param mixed $path
*/
public function setPath($path)
{
$this->path = $path;
}
The services os admin.yml
services:
sonata.admin.file:
class: DownloadFileAdminBundle\Admin\DownloadFileAdmin
arguments: [~, Opos\DownloadFileBundle\Entity\DownloadFile, SonataAdminBundle:CRUD]
tags:
- { name: sonata.admin, manager_type: orm, group: "Files", label: "Archivo" }
and services.yml:
services:
download_file_admin_bundle.vich_file_object_type:
class: DownloadFileAdminBundle\Form\Extension\VichFileObjectType
arguments: [ "#doctrine.orm.entity_manager" ]
tags:
- { name: "form.type", alias: "vich_file_object" }
And last vich and gaufrette configuration:
vich_uploader:
db_driver: orm
storage: gaufrette
mappings:
question_image:
uri_prefix: ~
upload_destination: questions_image_fs
namer: vich_uploader.namer_uniqid
download_file:
uri_prefix: ~
upload_destination: download_file_fs
namer: vich_uploader.namer_uniqid
knp_gaufrette:
stream_wrapper: ~
adapters:
questions_image_adapter:
local:
directory: %kernel.root_dir%/../web/images/questions
download_file_adapter:
local:
directory: %kernel.root_dir%/../web/files/download
filesystems:
questions_image_fs:
adapter: questions_image_adapter
download_file_fs:
adapter: download_file_adapter

VichUploaderBundle relies on Doctrine Events like pre persist/update to trgger its upload functionality. When you open existing entity in the admin section and upload new file without changing anything else, doctrine wouldn't dispatch lifecycle events as none of doctrine specific fields are changed.
So whenever new file object passed to the entity you need to update some doctrine specific field value, like updatedAt. Modify setDownloadFile of the entity to:
/**
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $file
*
* #return File
*/
public function setDownloadFile(File $file = null)
{
$this->downloadFile = $file;
if ($file) {
$this->updatedAt = new \DateTimeImmutable();
}
return $this;
}
Also you need to add updatedAt field and it's mapping in case you didnt.
Take a look at the example on VichUploaderBundle documentation page: https://github.com/dustin10/VichUploaderBundle/blob/master/Resources/doc/usage.md#step-2-link-the-upload-mapping-to-an-entity
UPDATE
Also you need to define form field on downloadFile property instead of path

Related

Vich Uploader integrate with Fly System cannot upload file but saved in database

I tried to create file upload by using vich uploader integrate with fly system in symfony.
However I only can save the file name in database but not uploading.
Is it something wrong with the flysystem or vich uploader setting?
Vich Uploader setting
vich_uploader:
db_driver: orm
storage: flysystem
mappings:
uploadedfile:
uri_prefix: /uploads
upload_destination: uploads.storage
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
flysystem setting
flysystem:
storages:
uploads.storage:
adapter: 'local'
options:
directory: '%kernel.project_dir%/public/uploads'
Entity
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\ImportFileRepository;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[ORM\Entity(repositoryClass: ImportFileRepository::class)]
#[Vich\Uploadable]
class ImportFile
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(type: 'string', length: 255)]
private $importFileName;
#[Vich\UploadableField(mapping: 'uploadedfile', fileNameProperty: 'importFileName')]
private ?File $importFile;
#[ORM\Column(type: 'datetime', columnDefinition: 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP')]
private $createdDate;
public function getId(): ?int
{
return $this->id;
}
/**
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $importFile
*/
public function setImportFile(?File $importFile = null): self
{
$this->importFile = $importFile;
if (null !== $importFile) {
$this->createdDate = new \DateTime('now');
}
return $this;
}
public function getImportFile(): ?File
{
return $this->importFile;
}
public function setImportFileName($importFileName): self
{
$this->importFileName = $importFileName;
return $this;
}
public function getImportFileName(): ?string
{
return $this->importFileName;
}
public function getCreatedDate(): ?\DateTimeInterface
{
return $this->createdDate;
}
public function setCreatedDate(\DateTimeInterface $createdDate): self
{
$this->createdDate = $createdDate;
return $this;
}
Controller
/**
*For build the form to twig
* #return Response
*/
#[Route('/import', name: 'import_index')]
public function index(): Response
{
// Build form for import csv
$form = $this->createFormBuilder()
->add('upload_file', VichFileType::class, [
'required' => true,
'allow_delete' => true,
'asset_helper' => true,
'attr' => ['class' => 'form-control'],
])
->getForm();
return $this->render('/admin/import/index.html.twig', ['form' => $form->createView(),]);
}
/**
* For persist data and file
* Save file by Vich Uploader integrate with FlySystem
* #param $file
* #return void
*/
private function saveFile($file){
$uploadFile = new ImportFile();
$uploadFile->setImportFileName($file->getClientOriginalName());
$uploadFile->setImportFile($file);
$this->entityManager->persist($uploadFile);
$this->entityManager->flush();
}
Because you are using php attributes, it looks like you may need to set the metadata.type key in your vich_uploader config (docs)
vich_uploader:
metadata:
type: attribute

There is no extension able to load the configuration for "vich_uploader"

I would like to use vich uploader in my easy admin interface. After installing it, I've created the vich_uploader.yaml file (it is not generating alone in my case).
I've follow the tutorial in the symfony page, but when I want to use it, an error occured :
"There is no extension able to load the configuration for "vich_uploader""
I really don't understand why, here is my files :
easy_admin.yaml :
easy_admin:
entities:
Project:
list:
fields:
- { property: 'photo_1', type: 'image', base_path: '%app.path.project_images%' }
show:
fields:
- { property: 'photo_1', type: 'image', base_path: '%app.path.project_images%' }
form:
fields:
- {property: 'photo_1File', type: 'vich_image'}
vich_uploader.yaml :
vich_uploader:
db_driver: orm
mappings:
project_images:
uri_prefix: '%app.path.project_images%'
upload_destination: '%kernel.project_dir%/public%app.path.project_images%'
My project entity looks like :
/**
* #ORM\Entity(repositoryClass=ProjectRepository::class)
* #Vich\Uploadable
*/
class Project
{
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #var string
*/
private $photo_1;
/**
* #Vich\UploadableField(mapping="project_images", fileNameProperty="photo_1")
* #var File
*/
private $photo_1File;
public function getPhoto1(): ?string
{
return $this->photo_1;
}
public function setPhoto1(?string $photo): self
{
$this->photo_1 = $photo;
return $this;
}
public function setPhoto1File(File $image = null)
{
$this->photo_1File = $image;
if ($image) {
$this->updatedAt = new \DateTime('now');
}
}
public function getPhoto1File()
{
return $this->photo_1File;
}
services.yaml :
parameters:
app.path.project_images: /uploads/images/projects
I've the line "vich/uploader-bundle": "^1.15" in my composer.json. It looks like symfony doesn't found the package...
Add to bundles.php:
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
This will activate the bundle for all environment, not only dev and test otherwise it won't be available on live environment

VichUploader: reupload image on entity update

I have entity Asset with field image
/**
* #ORM\Table(name="asset")
* #ORM\Entity(repositoryClass="AppBundle\Repository\AssetRepository")
* #Vich\Uploadable
*/
class Asset
{
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="assets")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* #ORM\Column(name="image", type="string", length=255, nullable=true)
*/
private $image;
/**
* #Vich\UploadableField(mapping="assets", fileNameProperty="image")
* #var File
*/
protected $imageFile;
I am using VichUploader to upload images to S3 bucket. I created custom namer to create file name. During upload entity is uploaded to folder with category name and is named with entity name
public function name($obj, PropertyMapping $mapping)
{
$category = $obj->getCategory()->getName();
$name = $obj->getName();
$file = $mapping->getFile($obj);
if ($extension = $this->getExtension($file)) {
$name = sprintf('%s.%s', $name, $extension);
}
return $category.'/'.$name;
}
These my upload configurations
oneup_flysystem:
adapters:
assets_adapter:
awss3v3:
client: app.assets.s3
bucket: '%assets_bucket%'
prefix: assets
filesystems:
assets_fs:
adapter: assets_adapter
mount: assets_fs
vich_uploader:
db_driver: orm
storage: flysystem
mappings:
assets:
delete_on_remove: true
delete_on_update: true
uri_prefix: 'https://s3-%assets_region%.amazonaws.com/%assets_bucket%/'
upload_destination: assets_fs
namer: app.asset_namer
I have following situation: user changes category of Asset. How file can be re-uploaded to new category folder and update name?
UPDATE
I am using EasyAdminBundle. Which handles create and edit entities. So I didn't create FormType and Controller for Asset entity. Here are configs:
easy_admin:
entities:
Asset:
class: AppBundle\Entity\Asset
label: 'Assets'
form:
fields:
- name
- {property: 'category', type: entity, type_options: {expanded: false, multiple: false, class: 'AppBundle:Category', required: true}}
- {property: 'imageFile', type: 'vich_image' }
One solution would be to update the Asset::setCategory method logic, to create a new File object when the category name is changed, and pass it to Asset::setImageFile to cause VichUploader to run the update process.
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* #ORM\Table(name="asset")
* #ORM\Entity(repositoryClass="AppBundle\Repository\AssetRepository")
* #Vich\Uploadable
*/
class Asset
{
//...
public function setCategory(Category $category)
{
if ($this->imageFile && $this->category->getName() !== $category->getName()) {
$this->setImageFile(new UploadedFile(
$this->imageFile->getRealPath(), //physical path to image file
$this->image, //current image name
null,
null,
null,
true
));
}
$this->category = $category;
return $this;
}
}
One issue is that by default VichUploader does not populate the entity imageFile property.
To ensure Asset::$imageFile is available, without needing to interact with the vich_uploader.storage service, you will need to add inject_on_load: true to your vich_uploader.mappings settings. This will add a listener to the entity to automatically populate the imageFile property with a File object.
#app/config/config.yml
#...
vich_uploader:
db_driver: orm
storage: flysystem
mappings:
assets:
delete_on_remove: true
delete_on_update: true
uri_prefix: 'https://s3-%assets_region%.amazonaws.com/%assets_bucket%/'
upload_destination: assets_fs
namer: app.asset_namer
inject_on_load: true
The prefered method would be to add the logic to your controller edit action, or adding a custom event subscriber to a Symfony event that monitors the Asset entity. Though I am not aware of how to accomplish this in relation to a category name change in EasyAdminBundle.

EasyAdminBundle and VichUploaderBundle - Error: The expected argument of type"", "Symfony\Component\HttpFoundation\File\UploadedFile" given

I'm using EasyAdminBundle for entity management and to upload images I want to useVichUploaderBundle.
Following the documentation configure the Bundle:
https://github.com/javiereguiluz/EasyAdminBundle/blob/master/Resources/doc/integration/vichuploaderbundle.rst
I do not use annotations but yml as described in the documentation:
https://github.com/dustin10/VichUploaderBundle/blob/master/Resources/doc/mapping/yaml.md
My code looks like this:
//app/config/config.yml
vich_uploader:
db_driver: orm
mappings:
torneo_images:
uri_prefix: '%app.path.torneo_images%'
upload_destination: '%kernel.root_dir%/../web/uploads/images/torneos'
..........
easy_admin:
form:
fields:
- logo
- { property: 'imageFile', type: 'file' }
The yml configuration file:
//BackendBundle/Resources/config/doctrine/Torneos.orm.yml
......
logo:
type: string
nullable: true
length: 255
options:
fixed: false
imageFile:
mapping: torneo_images
filename_property: logo
Add to Entity
//BackendBundle/Entity/Torneos.orm.yml
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\PropertyMapping as Vich;
namespace BackendBundle\Entity;
.......
/**
* #var string
*/
private $logo;
/**
* #var File
*/
private $imageFile;
.......
/**
* Set logo
*
* #param string $logo
*
* #return Torneos
*/
public function setLogo($logo)
{
$this->logo = $logo;
return $this;
}
/**
* Get logo
*
* #return string
*/
public function getLogo()
{
return $this->logo;
}
/**
* 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
*
* #return Torneos
*/
public function setImageFile(File $logo = null)
{
$this->imageFile = $logo;
// VERY IMPORTANT:
// 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
//if ($image) {
// if 'updatedAt' is not defined in your entity, use another property
// $this->updatedAt = new \DateTime('now');
//}
return $this;
}
/**
* #return File|null
*/
public function getImageFile()
{
return $this->imageFile;
}
Also add this code (I'm not sure if it's correct)
//BackendBundle/Resources/config/vich_uploader/Torneos.orm.yml
BackendBundle\Entity\Torneos:
imageFile:
mapping: torneo_images
filename_property: logo
Can anyone give me some idea to fix it?
The solution was quite simple.
The error occurs because the use are placed before thenamespace in the controller.
namespace BackendBundle\Entity;
Regards

ReflectionException with Symfony and Sonata, "Class does not exist"

I'm experiencing a problem trying to fit my Entities in the Sonata Admin Bundle. I have something like 5 entities, which are finely listed and viewed in the bundle, but I cannot edit or create a new entry.
When I try to edit or create, I get a ReflectionException error:
Class does not exist
I tried in order to solve that problem to operate on namespaces (moving controller in the same namespace that Admin files, or so) or to tweak the Admin Controller in order to tell it about my entities ("->add('individual', 'entity', array('class' => 'Platform\ProjectBundle\Entity\Individual'))" instead of ->add('individual')).
My entity is named Biosample. Here is the Entity file:
<?php
namespace Platform\ProjectBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="biosample")
*/
class Biosample
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Individual", inversedBy="samples")
* #ORM\JoinColumn(name="individual_id", referencedColumnName="id")
*/
protected $individual;
/**
* #ORM\Column(type="string", length=100)
*/
protected $organ;
/**
* #ORM\Column(type="string", length=100)
*/
protected $sample_name;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $organ_location;
/**
* #ORM\Column(type="string")
*/
protected $tissue_type;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $tissue_subtype;
/**
* #ORM\Column(type="datetimetz")
*/
protected $sampling_date;
/**
* #ORM\Column(type="decimal", scale=3, nullable=true)
*/
protected $cellularity;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $conservation;
/**
* #ORM\Column(type="text", nullable=true)
*/
protected $description;
/**
* #ORM\ManyToMany(targetEntity="Project", mappedBy="biosamples")
*/
protected $projects;
public function __construct()
{
$this->projects = new ArrayCollection();
}
public function __toString()
{
return $this->sample_name;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set organ
*
* #param string $organ
* #return Biosample
*/
public function setOrgan($organ)
{
$this->organ = $organ;
return $this;
}
/**
* Get organ
*
* #return string
*/
public function getOrgan()
{
return $this->organ;
}
/**
* Set organ_location
*
* #param string $organLocation
* #return Biosample
*/
public function setOrganLocation($organLocation)
{
$this->organ_location = $organLocation;
return $this;
}
/**
* Get organ_location
*
* #return string
*/
public function getOrganLocation()
{
return $this->organ_location;
}
/**
* Set tissue_type
*
* #param string $tissueType
* #return Biosample
*/
public function setTissueType($tissueType)
{
$this->tissue_type = $tissueType;
return $this;
}
/**
* Get tissue_type
*
* #return string
*/
public function getTissueType()
{
return $this->tissue_type;
}
/**
* Set tissue_subtype
*
* #param string $tissueSubtype
* #return Biosample
*/
public function setTissueSubtype($tissueSubtype)
{
$this->tissue_subtype = $tissueSubtype;
return $this;
}
/**
* Get tissue_subtype
*
* #return string
*/
public function getTissueSubtype()
{
return $this->tissue_subtype;
}
/**
* Set sampling_date
*
* #param \DateTime $samplingDate
* #return Biosample
*/
public function setSamplingDate($samplingDate)
{
$this->sampling_date = $samplingDate;
return $this;
}
/**
* Get sampling_date
*
* #return \DateTime
*/
public function getSamplingDate()
{
return $this->sampling_date;
}
/**
* Set cellularity
*
* #param string $cellularity
* #return Biosample
*/
public function setCellularity($cellularity)
{
$this->cellularity = $cellularity;
return $this;
}
/**
* Get cellularity
*
* #return string
*/
public function getCellularity()
{
return $this->cellularity;
}
/**
* Set conservation
*
* #param string $conservation
* #return Biosample
*/
public function setConservation($conservation)
{
$this->conservation = $conservation;
return $this;
}
/**
* Get conservation
*
* #return string
*/
public function getConservation()
{
return $this->conservation;
}
/**
* Set description
*
* #param string $description
* #return Biosample
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set individual
*
* #param \Platform\ProjectBundle\Entity\Individual $individual
* #return Biosample
*/
public function setIndividual(\Platform\ProjectBundle\Entity\Individual $individual = null)
{
$this->individual = $individual;
return $this;
}
/**
* Get individual
*
* #return \Platform\ProjectBundle\Entity\Individual
*/
public function getIndividual()
{
return $this->individual;
}
/**
* Add projects
*
* #param \Platform\ProjectBundle\Entity\Project $projects
* #return Biosample
*/
public function addProject(\Platform\ProjectBundle\Entity\Project $projects)
{
$this->projects[] = $projects;
return $this;
}
/**
* Remove projects
*
* #param \Platform\ProjectBundle\Entity\Project $projects
*/
public function removeProject(\Platform\ProjectBundle\Entity\Project $projects)
{
$this->projects->removeElement($projects);
}
/**
* Get projects
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProjects()
{
return $this->projects;
}
/**
* Set sample_name
*
* #param string $sampleName
* #return Biosample
*/
public function setSampleName($sampleName)
{
$this->sample_name = $sampleName;
return $this;
}
/**
* Get sample_name
*
* #return string
*/
public function getSampleName()
{
return $this->sample_name;
}
}`
Here is my BiosampleAdmin.php:
<?php
namespace Platform\ProjectBundle\Controller\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Platform\ProjectBundle\Entity\Biosample;
class BiosampleAdmin extends Admin
{
/**
* #param \Sonata\AdminBundle\Show\ShowMapper $showMapper
*
* #return void
*/
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
->add('id')
->add('sample_name')
->add('individual', 'entity', array('class' => 'Platform\ProjectBundle\Entity\Individual'))
->add('organ')
->add('organ_location')
->add('tissue_type')
->add('tissue_subtype')
->add('sampling_date')
->add('cellularity')
->add('conservation')
->add('projects', 'entity', array('class' => 'Platform\ProjectBundle\Entity\Project'))
->add('description')
;
}
/**
* #param \Sonata\AdminBundle\Form\FormMapper $formMapper
*
* #return void
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('General')
->add('sample_name')
->add('individual')
->add('organ')
->add('organ_location')
->add('tissue_type')
->add('tissue_subtype')
->end()
->with('Miscelaneous')
->add('sampling_date')
->add('cellularity')
->add('conservation')
->end()
->with('Projects')
->add('projects')
->end()
->with('Description')
->add('description', 'sonata_type_model', array('multiple' => false))
->end()
;
}
/**
* #param \Sonata\AdminBundle\Datagrid\ListMapper $listMapper
*
* #return void
*/
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id')
->add('sample_name')
->add('individual')
->add('projects')
->add('organ')
->add('tissue')
->add('_action', 'actions', array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
)
))
;
}
/**
* #param \Sonata\AdminBundle\Datagrid\DatagridMapper $datagridMapper
*
* #return void
*/
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('sample_name')
->add('individual')
->add('projects')
;
}
}
Here is the admin controller:
<?php
namespace Platform\ProjectBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Platform\ProjectBundle\Entity\Biosample;
class BiosampleAdminController extends Controller
{
}
And if you need it, here my composer.json:
{
"name": "symfony/framework-standard-edition",
"license": "MIT",
"type": "project",
"description": "The \"Symfony Standard Edition\" distribution",
"autoload": {
"psr-0": { "": "src/", "SymfonyStandard": "app/" }
},
"require": {
"php": ">=5.3.3",
"symfony/symfony": "2.6.*",
"doctrine/orm": "~2.2,>=2.2.3,<2.5",
"doctrine/dbal": "<2.5",
"doctrine/doctrine-bundle": "~1.2",
"twig/extensions": "~1.0",
"symfony/assetic-bundle": "~2.3",
"symfony/swiftmailer-bundle": "~2.3",
"symfony/monolog-bundle": "~2.4",
"sensio/distribution-bundle": "~3.0,>=3.0.12",
"sensio/framework-extra-bundle": "~3.0,>=3.0.2",
"jms/security-extra-bundle": "~1.2",
"ircmaxell/password-compat": "~1.0.3",
"stof/doctrine-extensions-bundle": "~1.1#dev",
"friendsofsymfony/user-bundle": "~1.3",
"incenteev/composer-parameter-handler": "~2.0",
"nervo/yuicompressor": "2.4.8",
"sonata-project/admin-bundle": "~2.3",
"sonata-project/doctrine-orm-admin-bundle": "~2.3",
"sonata-project/easy-extends-bundle": "~2.1",
"sonata-project/user-bundle": "~2.2",
"knplabs/knp-menu-bundle": "~1.1",
"mopa/bootstrap-bundle": "~2",
"twbs/bootstrap-sass": "~3.3.0",
"knplabs/knp-paginator-bundle": "dev-master",
"knplabs/knp-menu": "~1.1",
"craue/formflow-bundle": "~2.0"
},
"require-dev": {
"sensio/generator-bundle": "~2.3"
},
"scripts": {
"post-root-package-install": [
"SymfonyStandard\\Composer::hookRootPackageInstall"
],
"post-install-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles"
],
"post-update-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles"
]
},
"config": {
"bin-dir": "bin"
},
"extra": {
"symfony-app-dir": "app",
"symfony-web-dir": "web",
"symfony-assets-install": "relative",
"incenteev-parameters": {
"file": "app/config/parameters.yml"
},
"branch-alias": {
"dev-master": "2.6-dev"
}
}
}
Finally, here's my service declaration and my config.yml file:
Service.yml:
services:
platform.project.admin.biosample:
class: Platform\ProjectBundle\Controller\Admin\BiosampleAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: Project Manager, label: Biosample }
arguments: [null, Platform\ProjectBundle\Entity\Biosample, PlatformProjectBundle:BiosampleAdmin]
Config.yml:
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
framework:
#esi: ~
translator: { fallbacks: ["%locale%"] }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
default_locale: "%locale%"
trusted_hosts: ~
trusted_proxies: ~
session:
# handler_id set to null will use default session handler from php.ini
handler_id: ~
fragments: ~
http_method_override: true
# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
# Assetic Configuration
assetic:
debug: "%kernel.debug%"
use_controller: false
bundles: [ ]
#java: /usr/bin/java
filters:
cssrewrite: ~
#closure:
# jar: "%kernel.root_dir%/Resources/java/compiler.jar"
#yui_css:
# jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"
# Doctrine Configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: "%kernel.root_dir%/data/data.db3"
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
# path: "%database_path%"
types:
json: Sonata\Doctrine\Types\JsonType
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
# Swiftmailer Configuration
swiftmailer:
transport: "%mailer_transport%"
host: "%mailer_host%"
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
fos_user:
db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
firewall_name: secured
user_class: Application\Sonata\UserBundle\Entity\User
group:
group_class: Application\Sonata\UserBundle\Entity\Group
group_manager: sonata.user.orm.group_manager
service:
user_manager: sonata.user.orm.user_manager
sonata_doctrine_orm_admin:
entity_manager: ~
sonata_block:
default_contexts: [cms]
blocks:
sonata.admin.block.admin_list:
contexts: [admin]
sonata.user.block.menu: ~
sonata.user.block.account: ~
sonata.block.service.text: ~
sonata_user:
security_acl: true
manager_type: orm
mopa_bootstrap:
form: ~
And last but not least: the full stack trace.
[1] ReflectionException: Class does not exist
at n/a
in /var/www/Project/app/cache/dev/classes.php line 6756
at ReflectionClass->__construct('')
in /var/www/Project/app/cache/dev/classes.php line 6756
at Doctrine\Common\Persistence\AbstractManagerRegistry->getManagerForClass(null)
in /var/www/Project/vendor/sonata-project/doctrine-orm-admin-bundle/Model/ModelManager.php line 220
at Sonata\DoctrineORMAdminBundle\Model\ModelManager->getEntityManager(null)
in /var/www/Project/vendor/sonata-project/doctrine-orm-admin-bundle/Model/ModelManager.php line 54
at Sonata\DoctrineORMAdminBundle\Model\ModelManager->getMetadata(null)
in /var/www/Project/vendor/sonata-project/doctrine-orm-admin-bundle/Model/ModelManager.php line 317
at Sonata\DoctrineORMAdminBundle\Model\ModelManager->getIdentifierFieldNames(null)
in /var/www/Project/app/cache/dev/classes.php line 12663
at Sonata\AdminBundle\Form\ChoiceList\ModelChoiceList->__construct(object(ModelManager), null, null, null, null)
in /var/www/Project/app/cache/dev/classes.php line 13690
at Sonata\AdminBundle\Form\Type\ModelType->Sonata\AdminBundle\Form\Type\{closure}(object(OptionsResolver), object(SimpleChoiceList))
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/OptionsResolver/OptionsResolver.php line 836
at Symfony\Component\OptionsResolver\OptionsResolver->offsetGet('choice_list')
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/OptionsResolver/OptionsResolver.php line 769
at Symfony\Component\OptionsResolver\OptionsResolver->resolve(array('sonata_field_description' => object(FieldDescription), 'class' => null, 'model_manager' => object(ModelManager), 'multiple' => false, 'label_render' => false, 'label' => 'Description'))
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/Form/ResolvedFormType.php line 109
at Symfony\Component\Form\ResolvedFormType->createBuilder(object(FormFactory), 'description', array('sonata_field_description' => object(FieldDescription), 'class' => null, 'model_manager' => object(ModelManager), 'multiple' => false, 'label_render' => false, 'label' => 'Description'))
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php line 82
at Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->createBuilder(object(FormFactory), 'description', array('sonata_field_description' => object(FieldDescription), 'class' => null, 'model_manager' => object(ModelManager), 'multiple' => false, 'label_render' => false, 'label' => 'Description'))
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/Form/FormFactory.php line 87
at Symfony\Component\Form\FormFactory->createNamedBuilder('description', 'sonata_type_model', null, array('sonata_field_description' => object(FieldDescription), 'class' => null, 'model_manager' => object(ModelManager), 'multiple' => false, 'label_render' => false, 'label' => 'Description'))
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/Form/FormBuilder.php line 106
at Symfony\Component\Form\FormBuilder->create('description', 'sonata_type_model', array('sonata_field_description' => object(FieldDescription), 'class' => null, 'model_manager' => object(ModelManager), 'multiple' => false, 'label_render' => false, 'label' => 'Description'))
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/Form/FormBuilder.php line 268
at Symfony\Component\Form\FormBuilder->resolveChildren()
in /var/www/Project/vendor/symfony/symfony/src/Symfony/Component/Form/FormBuilder.php line 216
at Symfony\Component\Form\FormBuilder->getForm()
in /var/www/Project/app/cache/dev/classes.php line 9671
at Sonata\AdminBundle\Admin\Admin->buildForm()
in /var/www/Project/app/cache/dev/classes.php line 9930
at Sonata\AdminBundle\Admin\Admin->getForm()
in /var/www/Project/vendor/sonata-project/admin-bundle/Controller/CRUDController.php line 353
at Sonata\AdminBundle\Controller\CRUDController->editAction('1')
in line
at call_user_func_array(array(object(CRUDController), 'editAction'), array('1'))
in /var/www/Project/app/bootstrap.php.cache line 3022
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1')
in /var/www/Project/app/bootstrap.php.cache line 2984
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
in /var/www/Project/app/bootstrap.php.cache line 3133
at Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel->handle(object(Request), '1', true)
in /var/www/Project/app/bootstrap.php.cache line 2377
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
in /var/www/Project/web/app_dev.php line 28
Well, the reason for this error was a bad copy/paste from the tutorial.
In the Admin Class, the function configureFormFields contained a field "Description" badly described.
->with('Description')
->add('description', 'sonata_type_model', array('multiple' => false))
->end()
I had to replace it to:
->with('Description')
->add('description')
->end()
I discovered that automatic Admin Class skeleton generation was a function of Sonata Admin Bundle.
In order to automatically generate, execute:
php app/console sonata:admin:generate
Then enter the full path to your entity, in this example:
Platform\ProjectBundle\Entity\Biosample
The admin bundle will parse your entity and :
Generate the Admin Class file
Add an entry in your application bundle's service.yml
Generate optionnaly the CRUD controller
I guess this should be the prefered method when one is starting with sonata admin bundle.
I had the same problem, and for a reason i ignore, not in the past project where i've done exactly the same...
After an hour of search, i realize my table 'fos_user_user_group' has not been created has the mapping is not created. So my solution was simply to override the groups property of my entity User in order to define the Doctrine ORM Mapping :
/**
* The User can have many groups.
* #ORM\ManyToMany(targetEntity="Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
After that, doctrine:schema:update --force and the problem was solved ;)
If you did it like me, and created first the database then via the console the yml files and from that the classes, then your annotations are useless.
Sonata is using yml and not annotations. They exist and seem to work but they just don't. To make the "Class does not exist" message go check what you yml definitions are saying. I needed to add the relationships and entity classes there.
If this is really the reason for your errors you might want to activate the annotations by deleting or moving the yml or xml templates somewhere else (..\Resources\config\doctrine).

Categories