Load data from one model and structure it like it came from another
I have static and dynamic products on our website. Static products are your basic products that are loaded from a database. Dynamic products are user generated on the fly (from applications like "Design your own ring").
When a purchase is made, for each product sold there is an entry into a table/model called purchases, the purchase model holds the sale price, quantity, etc. for the product that was sold. the purchase model hasOne product.
This works fine for static products. However dynamic products need to have their data saved somewhere. I don't want to save the dynamic product to the products table because I don't want them showing up anywhere else except for purchases. Plus they also can contain extra values that static products don't have.
However, when I load the dynamic product data, I want it to be structured like a regular product, so I wont have to write different logic for processing static vs dynamic products.
I came up with the idea of creating a model/table called mavs (Model Attribute Values) with a table structure like so:
id purchase_id model attribute value
1 3 Product name foo
2 3 Product description bar
3 3 Other size 7
I would set purchase as hasMany mavs. The default way it would load this data though would look like this:
[Purchase] => Array
(
[0] => Array
(
...
[Product] => Array
(
)
[Mav] => Array
(
[0] => Array
(
[id] => 1
[purchase_id] => 78
[model] => Product
[attribute] => name
[value] => foo
)
[1] => Array
(
[id] => 2
[purchase_id] => 78
[model] => Product
[attribute] => description
[value] => bar
)
[2] => Array
(
[id] => 3
[purchase_id] => 78
[model] => Other
[attribute] => size
[value] => 7
)
)
)
)
I want to structure it like this:
[Purchase] => Array
(
[0] => Array
(
...
[Product] => Array
(
[name] => foo,
[description] => bar
)
[Other] => Array
(
[size] => 7
)
)
)
That way it will be able to be processed just like a regular product.
I thought I could achieve this by altering the data in the afterFind callback in the Mav model. I created this function:
public function afterFind( $results, $primary )
{
debug($results);
foreach($results as $key => $data)
{
$model = $data['Mav']['model'];
$attribute = $data['Mav']['attribute'];
$value = $data['Mav']['value'];
$results[$key] = array( $model => array( $attribute => $value ) );
}
debug($results);
return $results;
}
I am debuging the data before and after the change it goes from this:
Array
(
[0] => Array
(
[Mav] => Array
(
[id] => 1
[purchase_id] => 78
[model] => Product
[attribute] => name
[value] => foo
开发者_C百科 )
)
)
To this:
Array
(
[0] => Array
(
[Product] => Array
(
[name] => foo
)
)
)
which is exactly what I was intending. However the data I get from a $purchase->find()
is still structured in the original way. I am not sure why it is not reflecting my changes made in the afterFind callback.
So how can I acheive this? Also if anyone can offer better solutions to my problem all together, those are welcome too.
you are using $results twice.
create a new array with the data structure you like and return the new array.
I rewrote your function to do what you actually seemed to intend. See it working over here: http://codepad.org/8ajWNai8
function afterFind( $results, $primary )
{
foreach($results as &$currentResult)
{
foreach($currentResult["Mav"] as &$mavDetails)
{
$model = $mavDetails['model'];
$attribute = $mavDetails['attribute'];
$value = $mavDetails['value'];
if (!array_key_exists($model, $currentResult))
{
$currentResult[$model] = array();
}
$currentResult[$model][$attribute] = $value;
}
unset($currentResult["Mav"]);
}
return $results;
}
Since I have had zero exposure to CakePHP so far, this could be subtly wrong in the context. The function itself however seems to create exactly what you describe in your question.
精彩评论