Sergio Figueiredo Mon Jan 23 19:25:09 -0500 2012

Subject: Has support for embedded class?

Hi all,

I have some database tables with columns that I prefer handle as a embedded class. For instance, consider a 'Money' class with 'currency' and 'value' properties that is embedded in Order table:

Orders table
- id
- product_id
- price_currency
- price_value

but at class diagram:
Orders Class
- id (integer)
- product (Product class - it's ok. it is 'belongs_to' association)
- price (Money class - this is the problem!)

Money Class (a simple "Value Object" pattern)
- currency (string)
- value (decimal)

I need this, because is more easy convert currencies with functions that use Money class as parameter and return type.

Any idea?


Yoan B Sat Jan 28 09:57:48 -0500 2012

Your class logic could be correct, your database logic doesn't respect the normal forms. https://en.wikipedia.org/wiki/Normal_forms

You could do…

Orders
------
 - id
 - product_id
 - currency_id
 - price

Do you really only sell one product at the time?

Sergio Figueiredo Sat Jan 28 11:23:30 -0500 2012

My example is fake... ok, I will rename 'Order' to 'OrderItem' and imagine that I can put on a shopping cart products that is 'priced' by different currencies. Yes, this is not my real problem and look like a crazy example.

My actual question is that I would like load some fields of my table record to the entity class (Order class) and other fields to a another class (Money class). This embedded class (Money class) does not have your own 'id' property because it is not a entity and don´t need a respective table in a database because of your 'OneToOne' relationship. This idea of 'embedded class' is very common in JPA (http://docs.oracle.com/javaee/5/api/javax/persistence/Embedded.html).

I will use this table structure in this example:

OrderItems Table
----------------
 - id                : PK of OrderItems table
 - order_id          : FK to Order table
 - product_id        : FK to Products table
 - qty               : Quantity of this product
 - price_currency_id : FK to Currencies table
 - price_value       : The price of this product in this currency.

I have a suggestion to this framework. The embedded class could work like a new type of 'Association'. Like this:

class Money extends ActiveRecord\Embeddable {   
/* Money class is not a entity class. 
  Don´t have our own id
 and don´t need a table at database.
 But, can have associations to other tables:
*/
  static $belongs_to = array(
    array('currency', 'readonly' => true)
  );

 /**
  * Method that return a new Money instace 
  * with the value converted to a another currency.
  */
  function convertTo(currency) {
     // some implementation
  }
}

class OrderItem extends ActiveRecord\Model {
  static $belongs_to = array(
    array('order'),
    array('product', 'readonly' => true)
  );
  static $embedded = array(  // this is only a suggestion
     array('price', 'class_name'=>'money', field_prefix => 'price_' )  
    // 'class_name' and 'field_prefix'  can be optional
  );
}

// Creating a new OrderItem:
$order_item = new OrderItem();
$order_item->product = Product::find_by_barcode('123123123');
$order_item->price->currency = Currency::find_by_symbol('USD');
$order_item->price->value = 9.99;
$order_item->save();

// Add this item 'price->value' to Order 'total' converting the currency:
$order_item->order->total->value += $order_item->convertTo($order->total->currency);

All fields with 'price_' prefix on OrderItems database will be transferred to a new Money class and the reference at OrderItem Class is the 'price' property.

On save(), the framework will know that the 'price subclass' is not a table in a database because this is a 'Embeddable Association'. And will know that all property of Money class, will be prefixed by 'price_' at OrderItems table.

Is this possible? Is this issue understandable?

Yoan B Sat Jan 28 11:59:10 -0500 2012

It's understandable, but why? AR offers a “logical” mapping between your data (postgres, mysql, sqlite) and your model, you could hack something `OrderItem::get_price` to return a stdClass and stuff… but again, why?

What I can say is that PHP-AR cannot do that, and that I don't think it will in a near future, you're still free to fork it and adapt it for your needs and ideas.

Sergio Figueiredo Sat Jan 28 13:19:43 -0500 2012

Because the embedded class is useful to group related fields in a unique class to reuse operations. This help better structured code. I'm going to another example:

DBMS:

Subscribers Table:
-id
-subscribed_date_start
-subscribed_date_end
-payment_date_start
-payment_date_end
(more fields...)

PHP class model:

/* 
  DatePeriod class represents a period between dates.
*/
class Date_Period extends ActiveRecord\Embeddable {
}

class Subscriber extends ActiveRecord\Model {
  static $embedded = array( 
     array('subscribed_period', 'class_name'=>'date_period', 
           field_prefix => 'subscribed_' ),
     array('payment_period', 'class_name'=>'date_period', 
           field_prefix => 'payment_' )
  );
}

The advantage is that I have properties with standard names ('date_start' and 'date_end'). And not with field names ('subscribed_date_start','payment_date_start', ...). Now, I can write a set of functions (or methods) with 'date_period' operations:

function is_period_valid(period) {
  return (period->date_start <= period->date_end);
}

function days_in_period(period) {
  // another implementation
}

$subscriber = Subscriber::find(765);
if (is_period_valid($subscriber->subscribed_period) ) {
   // some code...
}
if (is_period_valid($subscriber->payment_period) ) {
   // some another code...
}

This is a very simple example that really don´t justify this feature because date_period class has only 2 properties. But, in real world, we can have related fields with more attributes ('commercial_address' and 'residential_address') or with associations with other tables (like 'currency_id' of 'Money class' in the previous post example).

I hope that I could showed the potential of this solution. This is not my idea. Another frameworks have used this.

(In my previous post I asked about the understandable of the issue only because the English is not my native language. I hope this have not considered a offense.)

Yoan B Sat Jan 28 14:04:50 -0500 2012

But, in real world, we can have related fields with more attributes (`commercial_address` and `residential_address`)

All I see here is that you want a legitimate way to violate database normal forms.

No offenses ;-)

To answer your initial question: PHP AR hasn't embedded models and it won't have any feature like that until you do it yourself.

(1-5/5)