Jump to content

Who understands how PS handles features?


Recommended Posts

For a script I am working to simulate the way Prestashop handles features (width, length, weight, etc).


Prestashop has the rather strange habit of - everytime you change a custom feature - to create a new id_feature_value while it deletes the old one. Yet it handles it as a change: only the target language is changed. Does anyone know whether this has any function?

Link to comment
Share on other sites

I've written scripts to import features via a source xml file and wrote my own way of handling it. Not sure if this is what you mean?


The main code to handle the "import" is within a custom admin controller (this includes removing features that are no longer present in the product entry as well as adding values that don't exist):


public function processProductFeatures($features, &$product)
    $_errors = array();
    $feed_features = array();

    // Check if there is anything to add
    if (!is_array($features))

    // Add each feature to the product
    foreach ($features as $feature)
	    $id_feature = Feature::addFeatureImport($feature['name']);
	    if ($id_feature)
		    $id_feature_value = FeatureValue::addPreDefFeatureValueImport($id_feature, $feature['value']);
		    if (!$id_feature_value)
			  $this->addProductWarning($feature['name'], isset($product->id) ? $product->id : null, 'Error adding new feature value. Value: '.$feature['value']);
		    $this->addProductWarning($feature['name'], isset($product->id) ? $product->id : null, 'Error adding new feature.');

	    if ($id_feature && $id_feature_value)
		    //$product->addFeaturesToDB($id_feature, $id_feature_value);
		    Product::addFeatureProductImport($product->id, $id_feature, $id_feature_value);
		    // maintain a list of the features for the product according to the feed
		    $feed_features[] = array('id_feature' => $id_feature, 'id_product' => $product->id, 'id_feature_value' => $id_feature_value);

    // Now get a complete list of features for a product -- We need to make sure that none have been
    // removed as per the feed, and if they have, we need to remove them from the site too.
    $store_features = $product->getFeatures();
    // Build an array of product features no longer in the feed
    $remove_features = array();
    if (is_array($store_features) && is_array($feed_features))
	    foreach ($store_features as $feature)
		    $in_feed = false;
		    foreach ($feed_features as $feed_feature)
			    if ($feature['id_feature'] == $feed_feature['id_feature'])
				    $in_feed = true;
		    if (!$in_feed)
			    $remove_features[] = array('id_feature' => $feature['id_feature'], 'id_feature_value' => $feature['id_feature_value']);
	    if (!empty($remove_features))
		    foreach ($remove_features as $remove_feature)
	    if (is_array($feed_features) && !is_array($store_features))
		    $_errors[] = Tools::displayError('(Product :'.$product->id.') Mismatch in attributes. Some features were not added.');
	    else if (!is_array($feed_features) && is_array($store_features))
		    $_errors[] = Tools::displayError('(Product :'.$product->id.') Mismatch in attributes. Some features could not be removed.');
    $this->_errors = array_merge($this->_errors, $_errors);
    return (empty($_errors) ? true : false);


The above uses a couple of extra functions added to the FeatureValue class (for convenience) via an override:


static public function addPreDefFeatureValueImport($id_feature, $name)
   $rq = Db::getInstance()->ExecuteS('
   SELECT fv.`id_feature_value`
   FROM '._DB_PREFIX_.'feature_value fv
   LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.`id_feature_value` = fv.`id_feature_value`)
   WHERE `value` = \''.pSQL($name).'\'
   AND fv.`id_feature` = '.(int)$id_feature.'
   GROUP BY fv.`id_feature_value` LIMIT 1');

   if (!isset($rq[0]['id_feature_value']) OR !$id_feature_value = (int)$rq[0]['id_feature_value'])
  // Feature doesn't exist, create it
  $featureValue = new FeatureValue();

  $languages = Language::getLanguages();
  foreach ($languages AS $language)
  	   $featureValue->value[$language['id_lang']] = strval($name);

  $featureValue->id_feature = (int)$id_feature;
  $featureValue->custom = 0;

  return (int)$featureValue->id;
   return (int)$id_feature_value;

 static public function removeFromProduct($id_feature, $id_feature_value, $id_product)
   Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'feature_product`
						   `id_feature` = '.(int)$id_feature. ' AND
						   `id_feature_value` = '.(int)$id_feature_value. ' AND
						   `id_product` = '.(int)$id_product);


You'll see that I'm not passing multiple languages, since these don't exist in the feed I'm working with but you could easily pass the feature value "name" as a language array and modify the code accordingly. You would also need to override the addFeatureImport() function that already exists in the Feature class as it also only accepts a single language name (although the id returned will be the same regardless of language - it only matters when you're creating a new feature or feature value). In the SQL you would search for only one language "name" from the array you pass.


I never delete a feature value completely as in my case I want a standard set available (note that when adding a feature value $featureValue->custom = 0). I only remove a feature from a product if it is no longer specified in the feed.


Not sure if the above helps, but best of luck!


(Apologies for any typos as I've modified the above code examples from my own project to remove any irrelevant code!)



  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...