Reputation: 167
I would like to change the value from custom features (Product Features) (Artikeleigenschaften) in my own class.
To change product values is very simple:
$productObj = new Product($produktId);
$productObj->setFieldsToUpdate(array('ean13'));
$productObj->ean13 = "johndoo";
$productObj->save();
But is there a similar way to change the Product Features?
Upvotes: 4
Views: 4065
Reputation: 1
None of these suggestions worked for me. I had few requirements for this:
This worked for me
/**
* Add or customize feature value to product feature and assign it to product
*
* Creates the feature and the value if they dont exists already
*/
private function _upsertFeatureValueToProduct($product, $featureName, $featureValue, $custom = false)
{
$id_lang = null;
// this creates the feature if required and always returns the id_feature
$id_feature = (int) \Feature::addFeatureImport($featureName);
if ($custom) {
// create or find a custom value
$id_feature_value = (int) \FeatureValue::addFeatureValueImport($id_feature, $featureValue, $product->id, $id_lang, $custom);
// change the existing value to new
$feature_value = new \FeatureValue($id_feature_value);
// in all languages (source only gives one language data)
$feature_value->value = array_fill_keys(\Language::getIDs(false), $featureValue);
$feature_value->update();
// assign the feature to the product (not strictly required if this was a update but doesn't hurt)
Product::addFeatureProductImport($product->id, $id_feature, $id_feature_value);
} else {
// non custom values. we first need to add the value and then assign it
// prestashop uses lang to find the existing feature. use the default language
$id_lang = \Configuration::get('PS_LANG_DEFAULT');
// add or get the feature id for this value
$id_feature_value = (int) \FeatureValue::addFeatureValueImport($id_feature, $featureValue, null, $id_lang, $custom);
// NOTE: product can have the same feature multiple times. But in this case we only get one value from source and want to update the feature
// so before adding the featurevalue delete existing feature assignments
$this->_deleteProductFeatureValueAssignments($product->id, $id_feature);
// assign the feature to the product
Product::addFeatureProductImport($product->id, $id_feature, $id_feature_value);
}
// required? doesn't hurt :)
\Feature::cleanPositions();
}
/**
* Delete product feature value assingments
*
* There is no api for this.. idea stolen from
*
https://github.com/PrestaShop/PrestaShop/blob/2c059b93062ce25bbde22355982e651215544e81/classes/Product.php#L2673
*
* TODO: open feature request, and remove this when prestashop has an api for this.
*/
private function _deleteProductFeatureValueAssignments($id_product, $id_feature)
{
$sql = '
DELETE fp
FROM `' . _DB_PREFIX_ . 'feature_product` fp
LEFT JOIN `' . _DB_PREFIX_ . 'feature_value` fv
ON fv.`id_feature_value` = fp.`id_feature_value`
WHERE
fp.`id_product` = ' . (int) $id_product .
' AND fp.`id_feature` = ' . (int) $id_feature .
' AND `custom`=0
';
return \Db::getInstance()->execute($sql);
}
now I can call this all day long without getting duplicate values in features or in the products
$this->_upsertFeatureValueToProduct($product, 'size', 'L');
$this->_upsertFeatureValueToProduct($product, 'size', 'XL');
$this->_upsertFeatureValueToProduct($product, 'size', 'custom', true); // one custom size just for fun
$this->_upsertFeatureValueToProduct($product, 'size', 'L');
Leaves me with two ready made feature values L
and XL
and a product with size=L and size=custom
screenshot of product features
There might still be bugs, just got this working :D
Upvotes: 0
Reputation: 69
Product::addFeatureProductImport($productObjc->id, $id_feature, $id_feature_value);
This will assign the feature and its value to the product. But we need the id of the feature and values. The below code is working for me.
$feature = new Feature();
$feature->name = [
$lang_id => "string"
];
$feature->position = Feature::getHigherPosition() + 1;
$feature->add();
$featurevalue = new FeatureValue;
$featurevalue->id_feature = $feature->id;
$featurevalue->value = [
$lang_id => "string"
];
$featurevalue->add();
$product->addFeatureProductImport($product->id, $feature->id, $featurevalue->id);
Upvotes: 0
Reputation: 445
I created this function based upon ImportControlloer. Add this function to Product.php override and use it
/**
* Adds a feature value to a Product. If You want to have feature selected from dropdown leave $custom to false.
* @param int|$id_product
* @param int|$id_feature_group
* @param string|$feature_value
* @param bool|true $custom
* @param int|$id_lang
* @return bool
*/
public static function setFeatureValueToProduct($id_product, $id_feature_group, $feature_value, $custom = false, $id_lang)
{
$group_feature_obj = Feature::getFeature($id_lang, $id_feature_group);
if ($group_feature_obj){
$feature_name = $group_feature_obj['name'];
$feature_value = $feature_value ? trim($feature_value) : '';
$position = false;
if (!empty($feature_name) && !empty($feature_value)) {
$id_feature = (int)FeatureCore::addFeatureImport($feature_name, $position);
$id_feature_value = (int)FeatureValue::addFeatureValueImport($id_feature, $feature_value, $id_product, $id_lang, $custom);
if (Product::addFeatureProductImport($id_product, $id_feature, $id_feature_value)){
Feature::cleanPositions();
return true;
} else {
return;
}
}
} else {
return;
}
}
Example of use:
Product::setFeatureValue(1597, 15, 'Dracarys', false, 1);
It will upload Dropdown value "Dracarys" into product with ID 1597 and group feature with ID 15. If You want to make it custom value (not-predefined) just set 4th parametr to true.
Upvotes: 1
Reputation: 167
Here my solution: To Update Product Features you have to update 2 tables in your Database: ps_feature_value and ps_feature_value_lang
Do this with:
$id_feature_value = (int)FeatureValue::addFeatureValueImport
(
(int)$feature['id_feature'],
$newFeatureValue,
(int)$produktId,
$this->context->language->id,
1 // $custom
);
Product::addFeatureProductImport(
$produktId, (int)$feature['id_feature'], $id_feature_value
);
To Update Features with NOT custom Values use:
$arr = FeatureValue::getFeatureValueLang($id_dropdown);
foreach ( $arr AS $item)
if ($item['id_lang'] == $this->context->language->id)
{
$feature_val_name = $item['value'] ;
}
$id_feature_value = (int)FeatureValue::addFeatureValueImport
(
(int)$feature['id_feature'],
$feature_val_name,
$product->id,
$this->context->language->id,
false
);
$product->addFeatureProductImport( $product->id , (int)$feature['id_feature'], $id_feature_value );
Upvotes: 2
Reputation: 648
Mh, Ive never tried to do this, but you could try this:
Product::addFeatureProductImport($productObjc->id, $id_feature, $id_feature_value);
Upvotes: 1