6

I've got a problem setting up the Doctrine mapping correctly.

I have a CashRegister Entity which has a bin location and a return bin location. Both locations are from the same Type (BinLocation Entity).

Outgoing from CashRegister, CashRegister->getBinLocations() and CashRegister->getReturnBinLocations() are working fine, but how can I achieve that BinLocation->getCashRegisters() returns all CashRegister Entities that are referenced (binLocation + returnBinLocation)?

/**
 * CashRegister
 *
 * @ORM\Table(name="cash_registers")
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class CashRegister
{

    ...

    /**
     * @var BinLocation
     *
     * @ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters")
     * @ORM\JoinColumn(name="bin_location_id", referencedColumnName="id")
     */
    private $binLocation;

    /**
     * @var BinLocation
     *
     * @ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters")
     * @ORM\JoinColumn(name="return_bin_location_id", referencedColumnName="id")
     */
    private $returnBinLocation;


    /**
     * @return BinLocation
     */
    public function getBinLocation()
    {
        return $this->binLocation;
    }

    /**
     * @return BinLocation
     */
    public function getReturnBinLocation()
    {
        return $this->returnBinLocation;
    }

    ...

}

/**
 * BinLocation
 *
 * @ORM\Table(name="bin_locations")
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class BinLocation
{

    ...

    /**
     * @var CashRegister[]
     *
     * @ORM\OneToMany(targetEntity="CashRegister", mappedBy="binLocation") <= Here is the problem, in this case mappedBy need to be an array [binLocation, returnBinLocation]
     */
    private $cashRegisters;


    /**
     * @return CashRegister[]
     */
    public function getCashRegisters()
    {
        return $this->cashRegisters;
    }

    ...

}
Bas Peeters
  • 3,269
  • 4
  • 33
  • 49
ipsum
  • 1,042
  • 7
  • 17

2 Answers2

5

The simple answer is that you cannot. mappedBy accepts only one argument.

The solution to achieve what you want is however simple. Create a second property in BinLocation called: cashRegisters2 as follows:

/**
 * @var CashRegister[]
 *
 * @ORM\OneToMany(targetEntity="CashRegister", mappedBy="binLocation")
 */
private $cashRegisters;

/**
 * @var CashRegister[]
 *
 * @ORM\OneToMany(targetEntity="CashRegister", mappedBy="binLocation") 
 */
private $cashRegisters2;

Then merge the Collections in your getCashRegisters method.

/**
 * @return CashRegister[]
 */
public function getCashRegisters()
{
    return new ArrayCollection(
                      array_merge($cashRegisters->toArray(), $cashRegisters2->toArray())
    );
}

Also change your CashRegister mappings accordingly:

/**
 * @var BinLocation
 *
 * @ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters")
 * @ORM\JoinColumn(name="bin_location_id", referencedColumnName="id")
 */
private $binLocation;

/**
 * @var BinLocation
 *
 * @ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters2")
 * @ORM\JoinColumn(name="return_bin_location_id", referencedColumnName="id")
 */
private $returnBinLocation;

Note: I did not test the code. This example is to server guide only.

Note2: The ArrayCollection merge was inspired from here: https://stackoverflow.com/a/16871539/2853903

Community
  • 1
  • 1
Mark
  • 5,437
  • 2
  • 19
  • 29
  • 2
    Thanks Mark for your answer, but this solution looks a bit like a hack. After googeling a while (before i wrote this question) i noticed that only few peoples had the same problem. Is there maybe another way to implement it in a more (enterprisy) "doctrine" way? (classes, tables, everything can be changed the only requirement is that i can store the bin location and the return bin location to an cash register and get them properly back) – ipsum Jul 10 '15 at 06:12
  • The problem originates in the fact that you cannot indicate multiple `mappedBy` fields. As such you need to solve the problem with other functionality Doctrine offers you, an example being offered above. If you want core Doctrine functionality changes maybe try asking for them on Github? At this stage however all solutions you'll get will be "hacky" :) – Mark Jul 10 '15 at 14:12
0

I have also searched for solutions and made a patch for Doctrine so you can have custom_attributes linked to a variety of entity types.

Doctrine 2.6: https://github.com/danielbeeke/doctrine2/commit/2d8530176b872cb490c5c88b8c8e17d8d0091388 Doctrine 2.7: https://github.com/danielbeeke/doctrine2/commit/5bde696848ea9fe7035fadc4d46baa4c0d51f3a2

/**
 * @Entity
 * @Table(name="product")
 * @HasLifecycleCallbacks
 **/
class Product {

  /**
   * One Product has Many Attributes.
   *
   * @OneToMany(
   *   targetEntity="CustomAttribute",
   *   mappedBy="EntityId",
   *   mappedByType={
   *     "field": "EntityType",
   *     "value": "product"
   *   }
   * )
   *
   * @var $CustomAttributes ArrayCollection
   */
  protected $CustomAttributes;
}


/**
 * @Entity
 * @Table(name="custom_attribute")
 * @HasLifecycleCallbacks
 **/
class CustomAttribute_entity {

  /** @Id @Column(type="integer") @GeneratedValue */
  protected $Id;

  /**
   * Many Attributes have One Entity of the EntityType provided.
   * @ManyToOne(targetEntity="Product", inversedBy="CustomAttributes")
   * @JoinColumn(name="EntityId", referencedColumnName="Id")
   */
  protected $EntityId;

  /** @Column(type="string") */
  protected $EntityType;

  /** @Column(type="string") */
  protected $Type;

  /** @Column(type="string") */
  protected $Value;

}