How do I make alias / aggregate attributes?
From PHP on Trax
composed_of
- "name" - is the name of the association.
- "class_name" - specify the class name of the association. Use it only if that name can’t be inferred from the $name. So public $composed_of = "address"; will by default be linked to the Address class, but if the real class name is CompanyAddress, you’ll have to specify it with this option.
- "mapping" - array that specifies a number of mappings (attribute, parameter) that bind an attribute name to a constructor parameter on the value class.
<?php
class Customer extends ActiveRecord {
public $composed_of = array(
"name" => array(
"class_name" => "Name",
"mapping" => array(
"first_name" => "first",
"initials" => "initials",
"last_name" => "last"
)
)
);
}
?>
Example, a table of customer data might include columns used to store
the customer’s name—first name, middle initials, and surname, perhaps.
Inside our program, we’d like to wrap these name-related columns into a
single Name object; the three columns get mapped to a single PHP object,
contained within the customer model along with all the other customer
fields. And, when we come to write the model back out, we’d want the data
to be extracted out of the Name object and put back into the appropriate
three columns in the database.
<phpcode>
DB Table Model
Customers --------------------------> Customer
--------------- ----------------
id id
credit_limit credit_limit
first_name ------> Name -------------> name
initials ---l ----------- first_name
last_name ---l first initials
last_purchase initials last_name
purchase_count last last_purchase
purchase_count
Database Table:
create table customers (
id int not null auto_increment,
credit_limit decimal(10,2) default 100.0,
first_name varchar(50),
initials varchar(20),
last_name varchar(50),
last_purchase datetime,
purchase_count int default 0,
created_at datetime not null,
primary key (id)
);
Customer Model:
<?php
class Customer extends ActiveRecord {
public $composed_of = array(
"name" => array(
"class_name" => "Name",
"mapping" => array(
"first_name" => "first",
"initials" => "initials",
"last_name" => "last"
)
)
);
}
?>
Composite Value Object (all options)
<?php
class Name {
public $auto_map_attributes = false;
function __construct($params = array()) {
$this->first = $params['first'];
$this->initials = $params['initials'];
$this->last = $params['last'];
}
function __toString() {
return ($this->first . " " . $this->initials . " " . $this->last);
}
}
?>
Composite Value Object (simple)
<?php
class Name {
function __toString() {
return ($this->first . " " . $this->initials . " " . $this->last);
}
}
?>
Now that your composed_of is set up its really simple to use.
If you have a constructor for your composite object.
<?php
$name = new Name(array("first" => "Dwight", "initials" => "D", "last" => "Eisenhower"));
$customer = new Customer(array("credit_limit" => 1000, "name" => $name));
$customer->save();
$customer = $customer->find_first();
echo $customer->first_name."<br>"; #=> Dwight
echo $customer->name->first."<br>"; #=> Dwight
echo $customer->name->initials."<br>"; #=> D
echo $customer->name->last."<br>"; #=> Eisenhower
echo $customer->name."<br>"; #=> Dwight D Eisenhower
$customer->name = new Name(array("first" => "Harry", null, "last" => "Truman"));
$customer->save();
$customer->reload();
echo $customer->first_name."<br>"; #=> Harry
echo $customer->name->first."<br>"; #=> Harry
echo $customer->name->initials."<br>"; #=>
echo $customer->name->last."<br>"; #=> Truman
echo $customer->name."<br>"; #=> Harry Truman
?>
If you don't have a constructor for your composite object:
<?php
$name = new Name;
$name->first = "Dwight";
$name->initials = "D";
$name->last = "Eisenhower";
$customer = new Customer(array("credit_limit" => 1000, "name" => $name));
$customer->save();
$customer = $customer->find_first();
echo $customer->first_name."<br>";
echo $customer->name->first."<br>"; #=> Dwight
echo $customer->name->initials."<br>"; #=> D
echo $customer->name->last."<br>"; #=> Eisenhower
echo $customer->name."<br>"; #=> Dwight D Eisenhower
$name = new Name;
$name->first = "Harry";
$name->initials = null;
$name->last = "Truman";
$customer->name = $name;
$customer->save();
$customer->reload();
echo $customer->first_name."<br>"; #=> Harry
echo $customer->name->first."<br>"; #=> Harry
echo $customer->name->initials."<br>"; #=>
echo $customer->name->last."<br>"; #=> Truman
echo $customer->name."<br>"; #=> Harry Truman
?>
Notes
- You can save your composite object in the lib folder or the app/models folder and it should be auto included.
- If you define a constructor in your object, ActiveRecord will pass into your objects constructor an array of key => values according to what you defined in your composed_of -> mapping.
