Search code examples
phpdoctrinedbal

Generic/wildcard Entity class for multiple indentical structured set of tables


I'm rewriting some parts of a big SaaS ecommerce project, that has been built and extended for many years. The main parts are splitted, so I'm having a backend, a shop frontend and a regular landing page. Because of this I can rewrite the different parts but can't alter the database. It's a lot of mixed spaghetti procedural code, no separated function files etc. and a more or less bad DB-design.

As a start, I'll rewrite the shop frontend. The base is built by slim framework v3 and Doctrine ORM, in an OOP-manner.

For structuring the Entities I'm having a problem with the existing database schema. Every existing shop has its own set of tables (min 3x, max 5x) holding order info ($client_order, $client2_order, ...), cart info ($client_info, $client2_info, ...), and additional needed extras. I wouldn't want to have the amount of $total_shop*3 Entity files, with 100% same code in it.

So I thought about having something like abstracted/generic Shop-Entities that contain the properties of each table. This way I might get the $client beforehand, load the Entity and change the corresponding table.

Is this possible, and how would I build and use these very Entities?

Just for picturing it, what I mean, some pseudo-code:

// App\Entity\GenericShopOrder

/**
 * @ORM\Entity(repositoryClass="App\Repository\GenericShopOrderRepository")
 * @ORM\Table(name="###PROBLEMATIC###")   <-----
 */
class GenericShopOrder
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    protected $id = 0;

    /**
     * @ORM\Column(type="string", length=200)
     */
    protected $myString = '';

// ---------

// App\Controller\PseudoController

public function myMethod() {
  $db_name = "client1"; // gotten beforehand
  $Orders = $this->container->get(GenericShopOrderRepository::class)->#####setTable($db_name)#####->findAll();
}

Solution

  • I found a solution:

    • Remove the table annotation of the Entity
    • Use following snippet in the controller:
        $meta = $em->getClassMetadata('App\Entity\GenericShopOrder');
        $meta->setTableName($var."_info");
        $repo = $em->getRepository('App\Entity\GenericShopOrder');
    

    By using getClassMetadata the Entity gets loaded, and the additional setTableName assigns the corresponding table name. The Repo/Entity works normal after that - with a table assigned on code execution.