问题
Imagine you are developing a website using symfony2 and it's admin panel using Sonata Admin Bundle and of course imagine you have a class named Product which owns some Images. Image is also a class and you have set in Product a one to many relation-ship to Image class. So every image is owned by a product, so you want to manage Image Admin inside Product Admin classes.
So there are some problems you should to face with them. Would you please to tell how?
1. When you delete a product object, all images related to that product be deleted.
2. When you are in show product page or add new product page the picture of all of images display on page.
(Is there any solution without using sonata media bundle too?)
Thanks
I handle Image upload with Document class:
FstQst\WebBundle\Entity\Document:
type: entity
table: null
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
updated: # changed when files are uploaded, to force preUpdate and postUpdate to fire
type: datetime
nullable: true
format:
type: string
length: 25
nullable: true
lifecycleCallbacks:
prePersist: [ preUpload ]
preUpdate: [ preUpload ]
postPersist: [upload]
postUpdate: [upload]
postRemove: [removeUpload]
I have another class using Document for adding some features to image:
FstQst\WebBundle\Entity\Post:
type: entity
table: null
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
title:
type: string
length: 100
nullable: true
oneToOne:
document:
targetEntity: Document
joinColumn:
name: document_id
referencedColumnName: id
orphanRemoval: true
manyToOne:
site:
targetEntity: VisitablePoint
inversedBy: posts
joinColumn:
name: vPoint_id
referencedColumnName: id
lifecycleCallbacks: { }
And a class named VisitablePoint, which uses Post class:
FstQst\WebBundle\Entity\VisitablePoint:
type: entity
table: visitablePoint
id:
id:
type: integer
id: true
generator:
strategy: AUTO
oneToMany:
posts:
targetEntity: Post
mappedBy: site
orphanRemoval: true
lifecycleCallbacks: { }
I changed my classes names from Post to Image and from VisitablePoint to Product at my old post. Now I want when I go to VisitablePoint admin/show page I see pictures of Post object instead of their title. And of course in admin/edit page too.
And these are Admin Classes:
<?php
namespace FstQst\WebBundle\Admin;
use FstQst\WebBundle\Entity\Document;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class DocumentAdmin extends Admin
{
/**
* @param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('id')
->add('updated')
->add('_action', 'actions', array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
)
))
;
}
/**
* @param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('file', 'file', $this->getFieldOptionForImagePreview())
;
}
/**
* @param ShowMapper $showMapper
*/
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
->add('id')
->add('updated')
->add('format')
;
}
public function prePersist($image) {
$this->manageFileUpload($image);
}
public function preUpdate($image) {
$this->manageFileUpload($image);
}
protected function manageFileUpload(Document $image) {
if ($image->getFile()) {
$image->refreshUpdated();
}
}
protected function getFieldOptionForImagePreview($maxSize = 200){
if($this->hasParentFieldDescription()) { // this Admin is embedded
// $getter will be something like 'getlogoImage'
$getter = 'get' . $this->getParentFieldDescription()->getFieldName();
// get hold of the parent object
$parent = $this->getParentFieldDescription()->getAdmin()->getSubject();
if ($parent) {
$document = $parent->$getter();
} else {
$document = null;
}
} else {
$document = $this->getSubject();
}
// use $fileFieldOptions so we can add other options to the field
$fileFieldOptions = array('required' => false);
if ($document && ($webPath = $document->getWebPath())) {
// get the container so the full path to the image can be set
$container = $this->getConfigurationPool()->getContainer();
$fullPath = $container->get('request')->getBasePath().'/'.$webPath;
//$fileFieldOptions['help'] = '<img src="/uploads/documents/10.png" class="admin-preview" style="max-height: 200px; max-width: 200px"/>';
$fileFieldOptions['help'] = <<<START
<img src="$fullPath" style="max-height: {$maxSize}px; max-width: {$maxSize}px"/>
START;
}
return $fileFieldOptions;
}
}
<?php
namespace FstQst\WebBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class VisitablePointAdmin extends Admin
{
/**
* @param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('posts', 'sonata_type_model', array('multiple' => true, 'property' => 'title', 'label' => 'Image', 'required' => false))
;
}
/**
* @param ShowMapper $showMapper
*/
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
->add('posts', 'sonata_type_collection', ['label' => 'Images',
'required' => false, 'cascade_validation' => true,
'by_reference' => false], ['edit' => 'inline', 'inline' => 'table'])
->end()
;
}
}
回答1:
The One to Many relation
1. When you delete a product object, all images related to that product be deleted.
You can easily manage this kind of deletion with the orphanRemoval="true"
<?php
class Product{
[...]
/**
* @ORM\OneToMany(targetEntity="Event", mappedBy="day", orphanRemoval="true", cascade={"all"})
*/
private $images;
[...]
}
in yml, the configuration looks like:
oneToMany:
images:
targetEntity: Image
orphanRemoval: true
mappedBy: product
2. When you are in show product page or add new product page the picture of all of images display on page.
You have to use a sonata_type_collection in your configureFormFields or your configureShowFields method of your ProductAdmin class:
<?php
class ProductAdmin{
[...]
protected function configureFormFields(FormMapper $formMapper) {
$formMapper
->with('tab_images')
->add('images', 'sonata_type_collection', array(
'required' => false,
'cascade_validation' => true,
'by_reference' => false,
), array(
'edit' => 'inline',
'inline' => 'table',
))
->end()
;
}
[...]
}
Then provide a ImageAdmin with all you need to upload files. You might have to change settings because i took it from a personal project and i don't know if it's totally adapted to your needs.
Show images in Sonata
first configure your ImageAdmin as follow:
class ImageAdmin extends Admin
{
[...]
protected function configureShowFields(ShowMapper $showMapper) {
$showMapper
->add('myImageAttr', 'image', array(
'prefix' => '/',
))
;
}
[...]
protected function configureListFields(ListMapper $listMapper) {
$listMapper
->add('myImageAttr', 'image', array(
'prefix' => '/',
'width' => 100
))
;
}
}
then create template for your list_image and you show_image types:
Resources/views/CRUD/show_image.html.twig
{% extends 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
{% block field %}
{% if value %}
<img src="{% if field_description.options.prefix %}{{ field_description.options.prefix }}{% endif %}{{ value }}" />
{% endif %}
{% endblock %}
Resources/views/CRUD/list_image.html.twig
{% extends admin.getTemplate('base_list_field') %}
{% block field%}
{% spaceless %}
{% set width = field_description.options.width is defined ? field_description.options.width : 50 %}
{% set height = field_description.options.height is defined ? field_description.options.height : 50 %}
{% if value %}
<img src="{% if field_description.options.prefix is defined %}{{ field_description.options.prefix }}{% endif %}{{ value }}"
style="max-width:{{ width }}px; max-height:{{ height }}px;" />
{% else %}
<div class="no-image" style="width:{{ width }}px; height:{{ height }}px;"></div>
{% endif %}
{% endspaceless %}
{% endblock %}
finally, add this configuration into your app/config/config.yml
sonata_doctrine_orm_admin:
templates:
types:
show:
image: YourBundle:CRUD:show_image.html.twig
list:
image: YourBundle:CRUD:list_image.html.twig
(http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/templates.html)
来源:https://stackoverflow.com/questions/27667905/managing-one-to-many-entities-in-sonata-admin-bundle