Skip to content

Explicit Loading and Saving

Romans Malinovskis edited this page Apr 18, 2016 · 1 revision

Suppose you have multiple database connections. $mysql_db is your MySQL database and $mongo_db is your MongoDB database. Those database implementations are very different and the way how records are stored/loaded is also very vendor-dependant. As a developer you don't have to worry about technicalities.

Consider the following code:

$users = $mysql_db->add('Model_Admin');
foreach($users as $user) {
    $mongo_db->save($user);
}

We have initialized our business model and linked it up with MySQL, so when we use $users within a loop we are reading all data from MySQL table "user" (as defined by $table) property. This will also use condition type="admin". Inside our loop, we're saving $user model inside $mongo_db, which is an entirely different database.

So far we have only worked with Business Models, but surprisingly that's all we had to do. Databases, however, can be structured differently and you might need to do some tweaks as the data is saved/loaded. Persistence section explains how we map DM to PM.

Next lets try to load Model_Client record.

$client = $db->add('Model_Client')->load(20 ,['completed_orders']);
echo "This client has ".$client['completed_orders']);

In this example we use explicit loading of a client with id=20, but we instruct the model that we are only interested in ['completed_order'] field. Depending on how we are going to use our model, we can save some network traffic and CPU by only fetching the fields that we will need.

Lets modify the code to include some debug information.

$client = $db->add('Model_Client', ['debug'=>true])->load(20 ,['completed_orders']);
echo "This client has ".$client['completed_orders']);

This should now output the following query for you:

select id, (
  select count(*) from `order` `o` 
  where completed=1 and `o`.`user_id`=`user`.`id`
) `completed_orders` from user where id=20;

This query demonstrates how Expressions can be used to add more logic inside your query. Consider a situation, when you need to display some stats about the user:

  • number of completed_orders
  • number of orders
  • average order amount

Instead of creating 3 queries, you can now define necessary expressions before loading:

$client = $db->add('Model_Client', ['debug'=>true]);
$client->addExpression('total_orders')->set($client->ref('Order')->count());
$client->addExpression('average_amount')->set($client->ref('Order')->avg('amount'));

$client->load(20);
echo "This client has ".$client['completed_orders']." completed orders out of ".$client['total_orders'].
     "for average amount of ".$client['average_amount']);

The above code has still produced only a single query:

select id, (
  select count(*) from `order` `o` 
  where completed=1 and `o`.`user_id`=`user`.`id`
) `completed_orders`,
(
  select count(*) from `order` `o` 
  where `o`.`user_id`=`user`.`id`
) `total_orders`,
(
  select sum((
      select sum(amount) from order_item 
      where order_item.order_id = `o`.id
  )) `amount`  from `order` `o` 
  where `o`.`user_id`=`user`.`id`
) `total_orders`,
 from user where id=20;

As you examine the query, you might notice that even though we have used very similar code to calculate 2 new columns, the SQL for "amount" actually contains some additional sub-query.

To find out how this "amount" was defined for Model_Order see Expressions.

Finally in order to print out all the "incomplete" orders for our Client, we'll use the following code:

$client = $db->add('Model_Client')->load(10);

$active_orders = $client->ref('Order')->addCondition('isComplete', false);
foreach($active_orders as $order) {
  echo "Order: ".json_encode($order->get())."\n";
}

Continue reading to find out how our Relation Mapping is different from another implementations.