Doctrine ORM defining entity relationships based on JSON columns

65 Views Asked by At

Software versions:

  • PHP: 7.4
  • MySQL: 8.0
  • Doctrine ORM: 2.9.6

I have an application for placing orders with the following schemas:

CREATE TABLE couriers
(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE orders
(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    created_at DATETIME NOT NULL,
    shipped_at DATETIME,
    dtype VARCHAR(255) NOT NULL,
    meta JSON,
    PRIMARY KEY (id)
)

There are also entity classes for Courier, Order and ExpeditedOrder (a child of Order). Order and ExpeditedOrder are using Single Table Inheritance, so they are both backed by the same database table (orders).

/**
 * @Entity
 * @Table(name="couriers")
 */
class Courier
{
    // Fields listed here
}
/**
 * @Entity
 * @Table(name="orders")
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="dtype", type="string")
 * @DiscriminatorMap({"order" = "Order", "expeditedOrder" = "ExpeditedOrder"})
 */
class Order
{
    // Fields listed here
}
/**
 * @Entity
 */
class ExpeditedOrder extends Order
{
}

A small percentage of orders will be expedited and will require a courier. To avoid having to add a courier_id column to the orders table, which would be NULL for the majority of orders, I'm planning to put this in the meta column of the orders table (this will also allow for additional order types to be added at a later date, without having to edit the schema). For example, a non-expedited order would have the meta column value NULL and an expedited order would have:

{
  "courier_id": 1
}

In the ExpeditedOrder entity, I want to be able to access the relevant Courier object. Normally I would have something like this:

/**
 * @ManyToOne(
 *   targetEntity="Courier"
 * )
 * @JoinColumn(
 *   name="courier_id",
 *   referencedColumnName="id"
 * )
 */
protected Courier $courier;

Is there a way to achieve this when the association is stored inside a JSON column? Ideally I would like to be able to use the usual findBy, findOneBy etc. functions from EntityRepository (provided by Doctrine) to get all orders matching certain criteria (e.g. by created_at).

The alternative I can think of is to only access expedited orders via custom queries in an ExpeditedOrderRepository, but I'd prefer to re-use code if possible.

0

There are 0 best solutions below