Notice: Array to string conversion in features_override_features_export_render_addition() (line 533 of features_override.export.inc)

Sometimes $value_export is an array.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Peter Majmesku’s picture

Haveing the same problem. At admin/structure/features/features_override I'm getting this notice about a dozen times.

alison’s picture

I'm getting this, too. What version of PHP are you running? I've got 5.4.6. I ask because of this seems-similar-on-the-surface thread #1588596: Notice: Array to string conversion in features_export_prepare() (line 190 of features.export.inc) in the Features queue. The patch in #11 in that issue fixed most of my "Notice: Array to string conversion......." messages, but I'm still getting the features_override.export.inc line 533 one that you're seeing. Maybe a similar patch could help here?

mattsmith3’s picture

Confirming the same problem on my site. I get it on the Review Overrides page, and what's odd- none of my features are overridden.

And the plot thickens... the errors (and override page) both disappear when I dis features_override. (just confirming that this is features_override)

Luckily, I don't need it right at this moment (for this install), but I will soon.

amcgowanca’s picture

Recently I also came across this problem. Digging a little deeper, I can confirm that at times the $value_export variable is an array. Therefore, a simple resolution would be to simply invoke features_override_var_export once again. Though, I am not sure if this is the most appropriate solution, more digging required.

amcgowanca’s picture

After doing some further digging and in my case specifically, it seems to be the case in which the $var of the features_override_var_export is an object and has the method export as there is the possibility in which an object or an array is returned.

Particularly in my case, the Rules module's export data is an object in which has the export method. When browsing to the features/features_override page, the returned value of the export method is an array when it is invoked. Therefore, this is one of two things:

  1. It is a problem specifically with features_override module in which it does not recursively re-test the $output when returned from the $var->export()
  2. It is a problem the contrib module, in this case Rules, that does not return a string value from its export().

I am going to go with the first option, that this is a problem with features_override and not the Rules (or other contrib modules). Therefore, here attached is a revised patch that actually alters the features_override_var_export function itself.

In addition, I wanted to note that the export of the Rules config objects is not done so cleanly in my instances. Is this the case of others overrides that are objects and are exported? Or is it just rules?

mpotter’s picture

Not sure on this one. In Features, the features_var_export() does this for objects:

if (is_object($var)) {
$output = method_exists($var, 'export') ? $var->export() : features_var_export((array) $var, '', FALSE, $count+1);
}

So if $var->export() isn't returning a string, then that module is doing it wrong. Not sure how Rules is working with Features if it really returns an array instead of a string. But it doesn't seem like changing this in Features Override is the right way to go.

If anything I'm trying to remember why Features Override has it's own var_export routine instead of just using the one in Features itself that has gotten more attention and updates.

amcgowanca’s picture

@mpotter, I totally agree. This is most likely not the best place to be resolving the issue.

alexbarrett’s picture

Version: 7.x-2.0-beta2 » 7.x-2.0-rc2
Priority: Normal » Major
Issue summary: View changes
FileSize
3.73 KB

I've spent a while debugging this issue today and have created a patch that fixes these notices for me. This patch may also solve #1957886: Rules config problem: the string "Array" is printed to the feature, causing a syntax error or WSOD as it looks similar and I am no longer seeing the string "Array" in my list of overrides.

The fix is in _features_override_set_additions() and _features_override_set_deletions(). What is happening is:

  1. Foreach gets used on a subclass of RulesContainerPlugin in an attempt to iterate its properties.
  2. As RulesContainerPlugin implements IteratorAggregate it instead iterates over the object's $children property.
  3. Inside the loop calls to property_exists() are passed the keys of the items in $children instead of the property names of the object. These incorrectly fail because they do not interact with IteratorAggregate.

This patch uses get_object_vars() to return the objects actual properties so these can be iterated instead of the object itself.

It's possible that this patch may break things and - as I have no means of extensively testing it - it would be appreciated if someone more familiar with the Features and Features Override modules reviewed it.

Island Usurper’s picture

The given patch gets rid of the error, but doesn't export rules config overrides usefully.

@mpotter, if features_var_export() isn't checking that $var implements a particular interface, then $var->export() can do absolutely anything and not be wrong to do so. We have to check what $var->export() is supposed to do before it gets called. EntityDefaultFeaturesController::export() returns a $pipe array, and modifies an $export array by reference, but I don't know if those objects are used anywhere near features_var_export().

iStryker’s picture

Status: Active » Needs work

Patch #8 breaks view exports. You are able to export deletions, no problem, but no additions show up.

mpotter’s picture

Priority: Major » Normal
mpotter’s picture

The point in #9 is interesting, but probably should be posted over to the Features issue queue if features_var_export needs to be modified to check for a specific interface. Although I'm not sure there is any specific interface that can be tested in D7, so it might be one of those issues we just need to live with because there is no consistent object model for configuration exporting in D7.

The original use of the $object->export() was to support ctools and views, which blazed the object-oriented ground in D7. If another contrib module is adding an export() method that has a different signature (i.e., doesn't return a string) then I'd probably argue it's up to that module to comply with the pseudo-standards set by ctools.

mpotter’s picture

So, now I'm running into this issue with Features Override also (with Rules). Just having Rules on our site and trying to go to the "Review Overrides" page causes errors with Rules trying to call export() on the RulesCondition objects.

Figuring out how to exclude certain objects definitely needs to be solved for both Features and Features Override since people are starting to add their own export() functions to objects. Will likely add some hook mechanism to prevent certain objects from being exported since I can't really tell from the object itself if it's export function is meant for features or not.

B-Prod’s picture

There are several issues that come from a compatibility issue with the Rules module itself. This last exports recursively a rule component, based on the root element.

First issue: output format

The rules plugin export method renders a string only if the component is the root element.

So when Features Override tries to render a short extract of code for highlighting the changes, the rules RulesPlugin::export method returns an array if the changes affect only a child component (so not the root).

So the RulesPlugin::export method is not reliable to perform the export of a child component.

Second issue: gathering the available variables

The RulesPlugin::availableVariables method uses a recursive call to itself until reaching the root component. The recursion limit introduced by Features Override leads to a PHP error when calling $this->parent->stateVariables() on the parent property which is no longer an object but a string...

Conclusion

It seems really difficult to rely on the RulesPlugin::export method. A quick fix could be to modify the features_override_var_export function :

      if (method_exists($var, 'export') && !($var instanceof \RulesPlugin)) {
        $output = $var->export();
      }

This works, but the generated string is almost unreadable...

As this is really dirty, I didn't create a patch.

wizonesolutions’s picture

@B-Prod: Did you ever find a better solution to this? I'm running into exactly this, and I don't understand why the recursion prevention replaces the parent with a string instead of just, say, making it null. I wonder if we could check for objects that don't return strings and fall back to the case where the class doesn't have an export method instead of just trusting its output wholesale as we do now...

rolfmeijer’s picture

As a workaround, I exported the edited rule, unset the rule and than re-added it with the new config.

/**
 * Implements hook_default_rules_configuration_alter().
 */
function MODULE_default_rules_configuration_alter(&$configs) {
  // First remove the original rule, than add a modified
  // version with hook_default_rules_configuration().
  unset($configs['machine_name_of_some_rule']);
}

/**
 * Implements hook_default_rules_configuration().
 */
function MODULE_default_rules_configuration() {
  $configs = array();

  $configs['machine_name_of_some_rule2'] = entity_import('rules_config', '{ "machine_name_of_some_rule" : {
    // exported rule config goes here
  }
  }');

  return $configs;
}

Maybe there are more sophisticated methods of overwriting or modifying a rule.

btopro’s picture

patch I used to account for Array when it should have been converted to a string. My issue stemmed from Rules export returning array instead of string for export.

wizonesolutions’s picture

Version: 7.x-2.0-rc2 » 7.x-2.x-dev
Status: Needs work » Needs review
FileSize
1.34 KB

Ah, I remember this one. When it comes to Rules, this still fails because features_remove_recursion() does something evil to the parent field on its objects. Nonetheless, here's a re-roll of #17.

rahul_sankrit’s picture

I were facing the same issue :

Notice: Array to string conversion in features_override_features_export_render_addition() (line 428 of sites/all/modules/contrib/features_override/features_override.export.inc).
diff --git a/features_override.export.inc b/features_override.export.inc
index 745f9e068..b33b26cf4 100644
--- a/features_override.export.inc
+++ b/features_override.export.inc
@@ -378,7 +378,24 @@ function features_override_var_export($var, $prefix = '') {
     // Objects do not export cleanily.
     else {
       if (method_exists($var, 'export')) {
-        $output = $var->export();
+        $raw_output = $var->export();
+        // Ensure this is placed into a string format.
+        if (is_array($raw_output)) {
+          if (empty($raw_output)) {
+            $output = 'array()';
+          }
+          else {
+            $output = "array(\n";
+            foreach ($var as $key => $value) {
+              // Use normal var_export() on the key to ensure correct quoting.
+              $output .= '  ' . var_export($key, TRUE) . " => " . features_override_var_export($value, '  ', FALSE) . ",\n";
+            }
+            $output .= ')';
+          }
+        }
+        else {
+          $output = $raw_output;
+        }
       }
       elseif (get_class($var) === 'stdClass') {
         $output = '(object) ' . features_override_var_export((array) $var, $prefix);
@@ -401,7 +418,6 @@ function features_override_var_export($var, $prefix = '') {
   if ($prefix) {
     $output = str_replace("\n", "\n$prefix", $output);
   }
-
   return $output;
 }
 

Thanks for patch
#18 fixes the issue for me.

Thanks

GuyPaddock’s picture

Status: Needs review » Needs work

After applying this patch, the errors have gone away, but features override now indicates under "Additions" all of the parts of the rule that has been exported in the feature, like this:

  $data['my_rule_name'][0] = array(
      0 => array(
        'id' => NULL,
        'weight' => 0,
        'name' => NULL,
        'settings' => array(
          'data:select' => 'commerce-order:type',
          'op' => '==',
          'value' => 'commerce_order',
        ),
      ),
    );

Followed by deletions that look like this:

  unset($data['my_rule_name'][0]);
  unset($data['my_rule_name'][1]);
  unset($data['my_rule_name'][2]);
  unset($data['my_rule_name'][3]);
  unset($data['my_rule_name'][4]);
  unset($data['my_rule_name'][5]);

The rule being exported is a standard rule that was created in the DB and then exported. It is not an override of an existing rule exposed by any other module.

Curiously, the feature does not reflect as Overridden.

Not sure if it matters, but I also have the patch from #2020917: Fatal error: Call to a member function stateVariables() on a non-object applied.

AlfTheCat’s picture

Same as #20, but overall seems to fix the issue