Managing one to many entities in sonata admin bundle

ぃ、小莉子 提交于 2019-12-24 01:18:48

问题



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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!