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?
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?
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.
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.)
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)
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?