Question

I have a OneToMany Relationship between a ChartPage and a BaseChart:

1 ChartPage holds 1 BaseChart and 1 BaseChart holds many ChartPages

Charts are managed in a different bundle of my application, so they can be removed individually. What I like to have is, that Doctrine automatically removes the ChartPage.Chart reference when the Chart is deleted, but nothing else (not remove the ChartPage).

The other way around should leave everything as is: When I remove the ChartPage with a referenced BaseChart - nothing should happen (not delete the BaseChart)

I tried every combination with one of these: cascade="{detach,merge,refresh,remove,persist}" that I could think of, but I can't figure it out..

This is my mapping:

<?php
/**
 * Class ChartPage
 * @package VBCMS\Bundle\AdminBundle\Document\Page
 * @Serializer\AccessType("public_method")
 * @MongoDB\Document()
 */
class ChartPage extends BasePage {

  /**
   * @var BaseChart
   * @Serializer\Type("VBCMS\Bundle\StatisticBundle\Document\BaseChart")
   * @Serializer\Accessor(setter="setChartDeserialize")
   * @MongoDB\ReferenceOne(
   *  targetDocument="VBCMS\Bundle\StatisticBundle\Document\BaseChart",
   *  mappedBy="pages",
   *  cascade={"persist,detach,merge"}
   * )
   */
  protected $chart;

}

/

/**
 * Class BaseChart
 * @package VBCMS\Bundle\StatisticBundle\Document
 * @Serializer\AccessType("public_method")
 * @MongoDB\Document(
 *  collection="Chart",
 *  repositoryClass="VBCMS\Bundle\StatisticBundle\Repository\ChartRepository"
 * )
 */
class BaseChart {

  /**
   * @var BasePage[]|Collection
   * @Serializer\Exclude()
   * @MongoDB\ReferenceMany(
   *   targetDocument="VBCMS\Bundle\AdminBundle\Document\Page\ChartPage",
   *   inversedBy="chart",
   *   cascade={"persist,detach,merge"}
   * )
   */
  protected $pages;

}

The only idea I have left is to build a custom preRemove EventListener that sets the references back to NULL before a BasePage ist removed, but I hoped I could avoid this manual mess.

Was it helpful?

Solution

Doctrine MongoDB ODM's cascade functionality only operates in one direction. If you perform some lifecycle event on object A, which has a reference to B, we could cascade the persist/remove/etc over to B. There is a concept of orphan removal in ODM, which allows for automated removal of objects embedded or referenced in a one-to-one or one-to-many relationship. I don't believe it's documented in the ODM manual, but it's very similar to what is described in the ORM documentation for the feature.

In your case, you don't want any cascading functionality on removal of A; you want B to remain as-is.

On the flip side, you would like all references to B among A objects to be cleaned up when you manually remove a B object. Using a pre or postRemove listener is your best option for this, and provided you have indexed the reference on A, it should be a very trivial multi-update query to set the references to null where they once referred to the instance of B that is removed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top