ZF2 + Doctrine: Read data from a database via TableGateway and hydrate Doctrine entity including its related objects with it

I am developing a centralized management software for our legacy web shops. These shops have been developed by a third party and are quite old, so they use pretty old practices too. Orders and their related objects are stored in one single table, therefore this table has a lot of fields and is quite bloated. Our new management system uses a relational approach. I. e. I have a table order to store the orders and a table address to store all addresses. Each order references its shipping and billing address via foreign keys. Doctrine 2 is used for handling these entities and their relations.

Obviously I have to import the orders from the shops into the database of our management system. This happens by directly accessing the database of each shop, querying the order data and inserting it in the management system's own database.

I am using the ZF2 TableGateway to retrieve the data from the shops and I would like to hydrate my entities using Doctrine's DoctrineObject hydrator with as little processing as possible. However, out of the box the DoctrineObject hydrator expects related objects to be passed in nested arrays. Because I have not yet figured out if the TableGateway can produce a multi dimensional result, I have to process the received data manually before passing it to the hydrator.

// $shop_db is a configured \Zend\Db\Adapter\Adapter to
// access the shop's database
$orders_table = new TableGateway(['order' => 'shop_orders'], $shop_db);

$order_data = $orders_table
    ->select(
        function(Select $select) {
            $select->columns([
                // Note: I am renaming the source fields to 
                // their internal equivalent via aliases
                'source_order_id' => 'id',
                'remarks' => 'customer_remarks',
                'created_at' => 'order_date',
                // Prefix the shipping address data with
                // "shipping_address_" so we can easily 
                // extract it later
                'shipping_address_firstname' => 'safirst',
                'shipping_address_lastname' => 'salast',
                'shipping_address_company' => 'sacomp',
                'shipping_address_street' => 'sastreet',
                'shipping_address_zip_code' => 'sazip',
                'shipping_address_city' => 'sacity'
            ]);
            $select->order('id');
        }
    );

// Process each order so its data can be
// digested by the DoctrineObject hydrator
foreach($order_data as $order)
{
    // ...
    // extract each element that has the 
    // prefix "shipping_address_" from the $order
    // and copy it to a nested array $order['shipping_address']
    // ...
}

So, to avoid the manual processing, I can think of two possible solutions:

  1. find a way to make the TableGatway return multi dimensional results
  2. find a way to make the DoctrineHydrator able to populate related objects by prefixed array elements instead of nested arrays

We have been using Propel2 a couple of years ago and if I remember correctly, Propel's hydrator could automatically populate related objects from a single dimensional array via prefixes, quite similar to how I manually process the received data. The Doctrine hydrator can't do that as far as I could see, though I guess you could use strategies to accomplish this.

Before I dive deep into developing strategies or a derived TableGateway, does somebody know an out-of-the-box solution? Or is my current approach the best it can get?

Answers


I think your current process of mapping the data to the format that your hydrator expects would be the better as apposed to using the naming strategies (because you have a flat array and the hydrator requires a nested one).

You could even create a composite hydrator to encapsulate the mapping.

class MyHydrator implements HydratorInterface
{
    // The class that does the data conversion
    protected $mapper;

    // The doctrine hydrator
    protected $hydrator;

    public function hydrate($data, $object)
    {
        // Return the data to the format that is expected
        $data = $this->mapper->map($data);

        return $this->hydrator->hydrate($data, $object);
    }

    public function extract($object)
    {
        $data = $this->hydrator->extract($object);

        // Reverse the data into a flat structure
        return $this->mapper->unmap($data);
    }
}

Need Your Help

Out of Memory Killer activated for python script running a multiprocessing Queue?

python queue out-of-memory multiprocessing kill-process

I have written a python program that needs to run for multiple days at a time, because of the constant collection of data. Previously I had no issues running this program for months at a time. I

ClusterKey Attribute in DataStax C# Driver

c# cassandra datastax

I have been trying to get a test object mapping working using the attributes in the Datastax C# driver for Cassandra.