title: Managing one to many entities in sonata admin bundle
body: <p><br>
  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. <br>
  So there are some problems you should to face with them. Would you please to tell how?<br>
  1. When you delete a product object, all images related to that product be deleted.<br>
  2. When you are in show product page or add new product page the picture of all of images display on page. <br>
  (Is there any solution without using sonata media bundle too?)<br>
  Thanks</p>
  
  <p>I handle Image upload with Document class:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>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]</code></pre>
  </div>
  </div>
  </p>
  
  <p>I have another class using Document for adding some features to image:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>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: {  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>And a class named VisitablePoint, which uses Post class:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>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: {  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>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.
  <br>
  And these are Admin Classes:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;?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
              -&gt;add('id')
              -&gt;add('updated')
              -&gt;add('_action', 'actions', array(
                  'actions' =&gt; array(
                      'show' =&gt; array(),
                      'edit' =&gt; array(),
                      'delete' =&gt; array(),
                  )
              ))
          ;
      }
  
      /**
       * @param FormMapper $formMapper
       */
      protected function configureFormFields(FormMapper $formMapper)
      {
  
          $formMapper
              -&gt;add('file', 'file', $this-&gt;getFieldOptionForImagePreview())
          ;
      }
  
  
      /**
       * @param ShowMapper $showMapper
       */
      protected function configureShowFields(ShowMapper $showMapper)
      {
          $showMapper
              -&gt;add('id')
              -&gt;add('updated')
              -&gt;add('format')
          ;
      }
  
      public function prePersist($image) {
          $this-&gt;manageFileUpload($image);
      }
  
      public function preUpdate($image) {
          $this-&gt;manageFileUpload($image);
      }
  
      protected function manageFileUpload(Document $image) {
          if ($image-&gt;getFile()) {
              $image-&gt;refreshUpdated();
          }
      }
  
      protected function getFieldOptionForImagePreview($maxSize = 200){
          if($this-&gt;hasParentFieldDescription()) { // this Admin is embedded
              // $getter will be something like 'getlogoImage'
              $getter = 'get' . $this-&gt;getParentFieldDescription()-&gt;getFieldName();
  
              // get hold of the parent object
              $parent = $this-&gt;getParentFieldDescription()-&gt;getAdmin()-&gt;getSubject();
              if ($parent) {
                  $document = $parent-&gt;$getter();
              } else {
                  $document = null;
              }
          } else {
              $document = $this-&gt;getSubject();
          }
  
          // use $fileFieldOptions so we can add other options to the field
          $fileFieldOptions = array('required' =&gt; false);
          if ($document &amp;&amp; ($webPath = $document-&gt;getWebPath())) {
              // get the container so the full path to the image can be set
              $container = $this-&gt;getConfigurationPool()-&gt;getContainer();
              $fullPath = $container-&gt;get('request')-&gt;getBasePath().'/'.$webPath;
              //$fileFieldOptions['help'] = '&lt;img src="/uploads/documents/10.png" class="admin-preview" style="max-height: 200px; max-width: 200px"/&gt;';
              $fileFieldOptions['help'] = &lt;&lt;&lt;START
  &lt;img src="$fullPath" style="max-height: {$maxSize}px; max-width: {$maxSize}px"/&gt;
  START;
          }
  
          return $fileFieldOptions;
      }
  
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;?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
              -&gt;add('posts', 'sonata_type_model', array('multiple' =&gt; true, 'property' =&gt; 'title', 'label' =&gt; 'Image', 'required' =&gt; false))
          ;
      }
  
      /**
       * @param ShowMapper $showMapper
       */
      protected function configureShowFields(ShowMapper $showMapper)
      {
          $showMapper
               -&gt;add('posts', 'sonata_type_collection', ['label' =&gt; 'Images',
                  'required' =&gt; false, 'cascade_validation' =&gt; true,
                  'by_reference' =&gt; false], ['edit' =&gt; 'inline', 'inline' =&gt; 'table'])
              -&gt;end()
          ;
      }
  }</code></pre>
  </div>
  </div>
  </p>