I'm not 100% sure if this is a problem with field_collection, but it seems to be.

I'm trying to export a content type with Features and I get a PHP Parse Error when I copy the feature under sites/all/features/my_content_type/

PHP Parse error:  syntax error, unexpected '{' in /Users/user/Sites/sitename/sites/all/modules/features/play_content_type/play_content_type.features.field.inc on line 844, referer: http://sitename.dev/

When I create the feature without including any fields which are part of a field_collection, I don't get any errors.

Just asking here if anyone has this problem and where should I look to try to fix it?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mErilainen’s picture

It seems that there is something hairy going on here (the default_value of the field_instance doesn't have proper syntax according to parser):

<?php
  $fields['field_collection_item-field_premiere-field_premiere_date'] = array(
  'field_config' => array(
        'active' => '1',
        'cardinality' => '-1',
        'deleted' => '0',
        'entity_types' => array(),
        'field_name' => 'field_premiere',
        'foreign keys' => array(),
        'indexes' => array(),
        'module' => 'field_collection',
        'settings' => array(
          'path' => '',
        ),
        'translatable' => '0',
        'type' => 'field_collection',
      ),
      'field_instance' => array(
        'bundle' => 'play',
        'default_value' => array(
          0 => array(
            'entity' => {
              "item_id" : null,
              "field_name" : "field_premiere",
              "field_premiere_type" : { "und" : [] },
              "field_premiere_date" : { "und" : [
                  {
                    "value" : "2011-09-01 00:00:00",
                    "all_day" : true,
                    "show_todate" : false,
                    "value2" : "2011-09-01 00:00:00",
                    "timezone" : "Europe\/Helsinki",
                    "offset" : 10800,
                    "offset2" : 10800
                  }
                ]
              }
            },
          ),
        ),
?>
 ...

I have another date field also which is not inside a collection and that one works normally. On the other hand I have another field collection which has a text field and a node reference field, and they also work normally. So it seems that field collection doesn't like date fields inside it.

mErilainen’s picture

Priority: Normal » Minor
Status: Active » Closed (works as designed)

I had a default value for the date field for some reason, which I don't need. After removing the default value I can export the feature without breaking the site. But the issue is still valid if someone wants to export fields with default values, but I'll close this since I'm not sure if this has anything to do with field_collection anymore.

pcambra’s picture

Status: Closed (works as designed) » Active

This has happened to me exporting a field collection with default addressfield values.

svdhout’s picture

The same thing occurs to me when i try to enable a feature containg a field_collection.

I have a collection with a field 'List (text)' and the 'Check boxes/radio buttons' containing default values.

The error in the feature's code:

      'default_value' => array(
        0 => array(
          'entity' => {
            "item_id" : null,
            "field_name" : "field_languages",
            "field_languages_language" : { "und" : [] },
            "field_languages_skill" : { "und" : [ { "value" : "notions" } ] }
          },
        ),

Update: After removing the field_collection, and adding it again everything worked fine

rlnorthcutt’s picture

I got the same error message on my local and a 500 error on the dev server when trying to view the Features page.

Removing the default values removed one error (so thats still an issue), but it still happened. I finally tracked it down to a field collection that referenced another field collection. I created a field collection on a user profile (Profile2) for address with these fields:
- address1 (text)
- address2 (text)
- city (text)
- state (list)
- zip (integer)
- hours (field collection)

The Hours field collection contained 4 fields:
- day (text)
- start (list-float)
- end (list-float)
- closed (checkbox)

When exporting the feature, I got the error on my local and the 500 error on the server when clearing cache or trying to view the Features page. The only way I could fix it was either to overwrite the feature with an older one OR manually removing the field references in the field list .inc in the feature.

Now the errors are gone and I can access Features again, but the state of the feature never leaves "checking"...

rlnorthcutt’s picture

FYI - here is the error I get on my local:
"Parse error: syntax error, unexpected '{' in C:\wamp\www\swooperdeal\drupal\sites\all\modules\features\features.export.inc(574) : eval()'d code on line 242"

tim.plunkett’s picture

Title: PHP Parse error: syntax error, unexpected '{' when exporting a feature » PHP Parse error: syntax error, unexpected '{' when exporting a feature with a default value
Version: 7.x-1.0-beta2 » 7.x-1.x-dev
robert.laszlo’s picture

I am having the same problem. My Field Collection includes Address Field module fields (http://drupal.org/project/addressfield), and this module requires the use of a default value for Country (although the developers of the module are debating changing that). The result is that I can't export this content type as a Feature.

tim.plunkett’s picture

Priority: Minor » Normal

This is coming from entity.module's EntityAPIControllerExportable::export(): http://drupalcode.org/project/entity.git/blob/refs/heads/7.x-1.x:/includ...

It's called by entity_export(), which is in turn called by export_render(), which is kicked off by Entity's implementation of hook_features_export_render().

Field collection might have to define it's own import and export. Not sure what it would do instead though...

bofrost’s picture

Title: PHP Parse error: syntax error, unexpected '{' when exporting a feature with a default value » subscribe
bofrost’s picture

Title: subscribe » PHP Parse error: syntax error, unexpected '{' when exporting a feature with a default value
bofrost’s picture

same here... after exporting a feature with addressfield

tim.plunkett’s picture

Bevan’s picture

Title: PHP Parse error: syntax error, unexpected '{' when exporting a feature with a default value » Features should reliably wrap JSON strings with quotes in exported Feature packages
Project: Field collection » Features
Version: 7.x-1.x-dev » 7.x-1.0-beta4
Status: Active » Needs work

I think the bug is further upstream, in the Features module, probably in features_var_export() or something close to it.

Field Collection (and Entity API) render the exportable configuration for the default value of node-instances of a field collection as JSON with entity_var_json_export().

Features' exporter does not wrap the JSON in a string—possibly because it expects a PHP/var_export() string instead of JSON or because it thinks that the string is already a PHP/var_export() string. The formats look similar and any syntax detection with regex or character-searching would be difficult to implement and likely to be buggy.

I could not debug this further because the bug went away and Features began exporting the code fine, for no apparent reason. Possibly because I installed Strongarm or manually added single quotes around the unquoted JSON. However even after removing the field configuration from the Features-package and adding it to a new Features-package, I could not reproduce the bug. Odd.

chalee’s picture

@Bevan: You said in #14 above "I installed Strongarm or manually added single quotes around the unquoted JSON...". Can elaborate on where exactly you place the single quotes. below is the snippet of my code giving the error.

'field_instance' => array(
      'bundle' => 'contract',
      'default_value' => array(
        0 => array(
          '_weight' => NULL,
          'entity' => {
            "item_id" : null,
            "field_name" : "field_contract_parties",
            "field_party_reference" : { "und" : [] },
            "field_party_type" : { "und" : [ { "value" : "_none" } ] },
            "field_party_contact" : { "und" : [] }
          },
        ),
      ),
stevector’s picture

Bevan’s picture

chalee;

'field_instance' => array(
      'bundle' => 'contract',
      'default_value' => array(
        0 => array(
          '_weight' => NULL,
          'entity' => {
            "item_id" : null,
            "field_name" : "field_contract_parties",
            "field_party_reference" : { "und" : [] },
            "field_party_type" : { "und" : [ { "value" : "_none" } ] },
            "field_party_contact" : { "und" : [] }
          },
        ),
      ),

would become

'field_instance' => array(
      'bundle' => 'contract',
      'default_value' => array(
        0 => array(
          '_weight' => NULL,
          'entity' => '{
            "item_id" : null,
            "field_name" : "field_contract_parties",
            "field_party_reference" : { "und" : [] },
            "field_party_type" : { "und" : [ { "value" : "_none" } ] },
            "field_party_contact" : { "und" : [] }
          }',
        ),
      ),

to become syntactically correct PHP. I changed lines 6 and 12.

chalee’s picture

@Bevan: Thanks.

drubbels’s picture

Thanks @Bevan, worked for me too!

bschilt’s picture

I'm experiencing the same issue. I have a date field as part of a field collection. The potential solutions mentioned in the previous comments haven't worked for me yet.

bradjones1’s picture

This still needs a patch and I'm happy to help - though can anyone point me to the right place in Features module were the export actually happens? Re: any relation to Strongarm module, I have 7.x-2.0-beta4 installed and I still get this error... so using both modules in tandem doesn't seem to be a workaround (at least not for me.)

bradjones1’s picture

Following up on my own in #21:

Bevan said testing on the string to determine if it is JSON would be tough - but what about doing a json_decode() on the string and testing for NULL as the return value? Per the docs, if it doesn't evaluate, we should get NULL. (It also does so if the recursion limit is reached - but I'm guessing that's not much of an issue here.)

See attached patch that tries that approach. It seems to export properly (that is, the feature doesn't give a fatal error) but the feature gets stuck in an "overridden" status. drush fd says, "Feature is in its default state. No diff needed." and drush fr refuses to revert since "Current state already matches defaults." So I suspect there's something else that needs to change to make this a complete patch.

bradjones1’s picture

Version: 7.x-1.0-beta4 » 7.x-1.x-dev
Status: Needs work » Needs review

Marking this needs review to get some eyes on the above patch - There's open debate as to where the proper place for this patch should be - that is, inside Entity API or Features... Some definitive input from a maintainer might help to get this in the right place and incorporated?

tim.plunkett’s picture

Status: Needs review » Needs work
+++ b/features.export.incundefined
@@ -459,7 +459,11 @@ function features_var_export($var, $prefix = '', $init = TRUE) {
+        if(json_decode($export)) $export = "'" . $export . "'";

No one line conditionals, and mind the spaces after "if".

bradjones1’s picture

Status: Needs work » Needs review
FileSize
843 bytes

Thanks for the nudge on coding standards. Try this?

bradjones1’s picture

I am earnestly looking for some help on the best way to do this - case in point, the patch above addresses this issue, but has the side-effect of wrapping any other data that validates with json_decode() (booleans, integers, strings) in single-quotes. So at least the first time you update/diff your features after this is applied, you'll get a bunch of "false" changes as the files do indeed differ from the non-quoted versions on disk.

This may not be a huge issue at least for integers - they seem to be sometimes quoted anyway. Here's a diff just after a drush fua:

...
-        'nid' => 4,
+        'nid' => '4',
         'cid' => '1',
         'pid' => '0',
...

So there's a cid and pid that were quoted to begin with. I am however seeing some booleans (TRUE, FALSE) being quoted, which could be a problem?

bradjones1’s picture

Sorry for lengthening this - I believe the attached patch should be much closer. The second parameter to json_decode() is to return an associative array, which would be what we're getting as input (in a {} string) - so if we set that to TRUE, ints, bools and strings appear to pass through unchanged and unquoted.

Bevan’s picture

Brad; I am glad someone has the time and energy to fix this. I think there is a better way to fix this bug at an architectural level rather than detecting whether or not a string looks like JSON.

Someone with thorough understanding of the internals of Features, Entity API and Field Collection modules would likely be able to either provide comprehensive direction, or fix it quickly. They are usually busy people though and are probably most effectively sought directly via PM or IRC.

Bevan’s picture

mrfelton’s picture

Patch in #27 is working for me. Thanks.

hefox’s picture

Status: Needs review » Needs work
+++ b/features.export.inc
@@ -461,7 +461,13 @@ function features_var_export($var, $prefix = '', $init = TRUE) {
+        if (json_decode($export,TRUE)) {

space between $export, TRUE

I'm curious, if you call features_var_export on a something that will return a json, instead of an array of items that end up as json? I think the json detection is likely needed for whatever part returns the json (haven't looked into it at all to see if it's the object export code or the var_export fallback).

Also, is this a problem with ctools_var_export and drupal_var_export?

girishmuraly’s picture

+++ b/features.export.inc
@@ -461,7 +461,13 @@ function features_var_export($var, $prefix = '', $init = TRUE) {
+        if (json_decode($export,TRUE)) {
+          $export = "'" . $export . "'";
+        }

Why do we want to export in JSON format when we can decode it in features_var_export() anyway? For me, this lead to the Fatal error mentioned here #1281974: Missing bundle property on entity - related to translations on actually trying to create the content type that I just exported having a field collection field.

I had to wrap a drupal_json_decode() to the export itself like:

'field_instance' => array(
      'bundle' => 'awards',
      'default_value' => array(
        0 => array(
         // Wrapping in drupal_json_decode() so that entity_extract_ids() can read the 'field name' and pass through
          'entity' => drupal_json_decode('{
            "item_id" : null,
            "field_name" : "field_child_items",,
            "field_child_page" : { "und" : [] },
            "field_child_page_label" : { "und" : [] },
            "field_group_menu_add" : { "und" : [ { "value" : 0 } ] }
          }'),
        ),
      ),
jeffschuler’s picture

Patch in #27 worked for me.

ygerasimov’s picture

Status: Needs work » Needs review
FileSize
990 bytes

If we dig into Entity API on example of Field Collection, features_var_export() on FieldCollectionItemEntity object calls EntityAPIController::export() method. And this export() method calls entity_var_json_export() that is prettier looking drupal_json_encode().

Please review attached patch that will not enclose non-objects.

pwaterz’s picture

There is a problem with the above patch. When the json object get read back into drupal, it doesnt get json decoded. It directly related to this bug http://drupal.org/node/1281974

hefox’s picture

Status: Needs review » Needs work
pwaterz’s picture

I think #32 is on the right track.

pwaterz’s picture

Status: Needs work » Needs review
FileSize
1.14 KB

Here is an updated patch that should resolve the import issue.

KLicheR’s picture

Tested patch #38

We applied the patch on source and destination sites, exported the feature and re-imported it into the destination site. Then we went to add content of the type including the field collection concerned, and got this error:

EntityMalformedException: Missing bundle property on entity of type field_collection_item. in entity_extract_ids() (line 7501 of /home/quickstart/websites/test.dev/includes/common.inc).

Here is a dump of the pertinent lines in our field.inc:

      'default_value' => array(
        0 => array(
          'entity' => 'drupal_json_decode({
            "item_id" : null,
            "field_name" : "field_cdj_col_periodes",
            "field_cdj_taxo_periode" : { "und" : [] },
            "field_cdj_taxo_groupes_age" : { "und" : [] },
            "field_cdj_statut_inscr" : { "und" : [] },
            "field_cdj_complet" : { "und" : [ { "value" : 0 } ] }
          })',
        ),
      ),

We found it off that the entire drupal_json_decode() call was in single quotes, so we tried this again moving the single quotes to encapsulate the json string (drupal_json_decode('foo') instead of 'drupal_json_decode(foo)') - but continue to get the same error.

pwaterz’s picture

Can you go into common.inc where entity_extract_ids is defined and right before where is says 'throws new...' put 'debug($entity);' and paste those results here.

KLicheR’s picture

In response to #40:

Debug:

'drupal_json_decode({
            "item_id" : null,
            "field_name" : "field_cdj_col_periodes",
            "field_cdj_taxo_periode" : { "und" : [] },
            "field_cdj_taxo_groupes_age" : { "und" : [] },
            "field_cdj_statut_inscr" : { "und" : [] },
            "field_cdj_complet" : { "und" : [ { "value" : 0 } ] }
          })'

in entity_extract_ids() (line 7501 of /home/quickstart/websites/test.ah/includes/common.inc).

I founded that if a manually change the JSON object in the field.inc file, it work:
BEFORE

'default_value' => 'entity' => {
  "item_id" : null,
  "field_name" : "field_cdj_col_periodes",
  "field_cdj_taxo_periode" : { "und" : [] },
  "field_cdj_taxo_groupes_age" : { "und" : [] },
  "field_cdj_statut_inscr" : { "und" : [] },
  "field_cdj_complet" : { "und" : [ { "value" : 0 } ] }
},

AFTER

'default_value' => 'entity' => (object)array(
  "item_id" => null,
  "field_name" => "field_cdj_col_periodes",
  "field_cdj_taxo_periode" => array( "und" => array() ),
  "field_cdj_taxo_groupes_age" => array( "und" => array() ),
  "field_cdj_statut_inscr" => array( "und" => array() ),
  "field_cdj_complet" => array( "und" => array( array( "value" => 0 ) ) )
),

or

'default_value' => NULL,
danmuzyka’s picture

Status: Needs review » Needs work

This is a very difficult issue to solve...thanks to all who have worked on this so far.

I created a patch that exports entities in the format in the AFTER code block in #40. I found it worked OK until I did a features-revert, at which point the default_value stored in the field_config_instance table in the database was no longer correct. At that point, I could no longer edit my field_collection field nor save new article nodes (which have the field_collection attached to them).

Here is my Features-exported field_collection:

// Exported field: 'node-article-field_editorial_placement'
  $fields['node-article-field_editorial_placement'] = array(
    'field_config' => array(
      'active' => '1',
      'cardinality' => '1',
      'deleted' => '0',
      'entity_types' => array(),
      'field_name' => 'field_editorial_placement',
      'foreign keys' => array(),
      'indexes' => array(),
      'module' => 'field_collection',
      'settings' => array(
        'path' => '',
      ),
      'translatable' => '0',
      'type' => 'field_collection',
    ),
    'field_instance' => array(
      'bundle' => 'article',
      'default_value' => array(
        0 => array(
          'entity' => (object) array (
            'item_id' => NULL,
            'field_name' => 'field_editorial_placement',
            'field_sticky' =>
            array (
              'und' =>
              array (
                0 =>
                array (
                  'value' => '0',
                ),
              ),
            ),
            'field_stickyweight' =>
            array (
              'und' =>
              array (
              ),
            ),
            'field_promote_to_front' =>
            array (
              'und' =>
              array (
                0 =>
                array (
                  'value' => '0',
                ),
              ),
            ),
          ),
        ),
      ),
      'deleted' => '0',
      'description' => '',
      'display' => array(
        'default' => array(
          'label' => 'above',
          'module' => 'field_collection',
          'settings' => array(
            'add' => 'Add',
            'delete' => 'Delete',
            'description' => TRUE,
            'edit' => 'Edit',
            'view_mode' => 'full',
          ),
          'type' => 'field_collection_view',
          'weight' => 21,
        ),
        'teaser' => array(
          'label' => 'above',
          'settings' => array(),
          'type' => 'hidden',
          'weight' => 0,
        ),
      ),
      'entity_type' => 'node',
      'field_name' => 'field_editorial_placement',
      'label' => 'Editorial Placement',
      'required' => 0,
      'settings' => array(
        'user_register_form' => FALSE,
      ),
      'widget' => array(
        'active' => 0,
        'module' => 'field_collection',
        'settings' => array(
          'maxlength_js_label' => 'Content limited to @limit characters, remaining: <strong>@remaining</strong>',
        ),
        'type' => 'field_collection_embed',
        'weight' => '26',
      ),
    ),
  );

Here is an example of what the database had BEFORE the features-revert:

data column from field_config_instance

a:7:{s:5:"label";s:9:"Placement";s:6:"widget";a:5:{s:6:"weight";s:2:"26";s:4:"type";s:22:"field_collection_embed";s:6:"module";s:16:"field_collection";s:6:"active";i:0;s:8:"settings";a:1:{s:18:"maxlength_js_label";s:76:"Content limited to @limit characters, remaining: <strong>@remaining</strong>";}}s:8:"settings";a:1:{s:18:"user_register_form";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:21:"field_collection_view";s:8:"settings";a:5:{s:4:"edit";s:4:"Edit";s:6:"delete";s:6:"Delete";s:3:"add";s:3:"Add";s:11:"description";b:1;s:9:"view_mode";s:4:"full";}s:6:"module";s:16:"field_collection";s:6:"weight";i:21;}}s:8:"required";i:0;s:11:"description";s:0:"";s:13:"default_value";a:1:{i:0;a:1:{s:6:"entity";O:25:"FieldCollectionItemEntity":11:{s:13:" * hostEntity";N;s:15:" * hostEntityId";N;s:17:" * hostEntityType";N;s:11:" * langcode";N;s:7:"item_id";N;s:10:"field_name";s:25:"field_editorial_placement";s:13:" * entityType";s:21:"field_collection_item";s:6:"is_new";b:1;s:12:"field_sticky";a:1:{s:3:"und";a:1:{i:0;a:1:{s:5:"value";s:1:"0";}}}s:18:"field_stickyweight";a:1:{s:3:"und";a:0:{}}s:22:"field_promote_to_front";a:1:{s:3:"und";a:1:{i:0;a:1:{s:5:"value";s:1:"0";}}}}}}} 

Here is how the same table cell looked AFTER the features-revert:

data column from field_config_instance

 a:7:{s:13:"default_value";a:1:{i:0;a:1:{s:6:"entity";O:8:"stdClass":5:{s:7:"item_id";N;s:10:"field_name";s:25:"field_editorial_placement";
s:12:"field_sticky";a:1:{s:3:"und";a:1:{i:0;a:1:{s:5:"value";s:1:"0";}}}s:18:"field_stickyweight";a:1:{s:3:"und";a:0:{}}s:22:"field_promote_to_front";
a:1:{s:3:"und";a:1:{i:0;a:1:{s:5:"value";s:1:"0";}}}}}}s:11:"description";s:0:"";s:7:"display";a:2:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:6:"mo
dule";s:16:"field_collection";s:8:"settings";a:5:{s:3:"add";s:3:"Add";s:6:"delete";s:6:"Delete";s:11:"description";b:1;s:4:"edit";s:4:"Edit";s:9:"view
_mode";s:4:"full";}s:4:"type";s:21:"field_collection_view";s:6:"weight";i:21;}s:6:"teaser";a:4:{s:5:"label";s:5:"above";s:8:"settings";a:0:{}s:4:"type
";s:6:"hidden";s:6:"weight";i:0;}}s:5:"label";s:19:"Editorial Placement";s:8:"required";i:0;s:8:"settings";a:1:{s:18:"user_register_form";b:0;}s:6:"wi
dget";a:5:{s:6:"active";i:0;s:6:"module";s:16:"field_collection";s:8:"settings";a:1:{s:18:"maxlength_js_label";s:76:"Content limited to @limit charact
ers, remaining: <strong>@remaining</strong>";}s:4:"type";s:22:"field_collection_embed";s:6:"weight";s:2:"26";}}

If you look carefully, you'll see that in the first instance, the entity is stored as an object of class FieldCollectionItemEntity, whereas after the features-revert it is converted to a generic stdClass object. This, of course, is the limitation of converting the object to an array and then casting it as an object again.

Unfortunately, since the current approach is based on var_export(), which is not the most convenient way to store an object as a string, converting the object into an array and then casting it back to an object is the best method I know for getting an object into code using this method.

Perhaps we would be better off using serialize() instead of var_export() to store objects in features, but I have a feeling that approach would require a huge amount of code refactoring.

Any thoughts/suggestions?

pwaterz’s picture

+1 serialize

hefox’s picture

danmuzyka’s picture

I'm attaching my stopgap patch (that doesn't really solve the underlying issue) in case it helps illustrate the approach I described in the comment above.

@hefox It is not exactly the same issue...in this case, there is actually an existing export method for Field Collections (class FieldCollectionItemEntity), which they inherit from the Entity API module (class Entity). The Entity::export() method calls EntityAPIController::export(), which generates the JSON code that is being discussed in this ticket:

  /**
   * Implements EntityAPIControllerInterface.
   *
   * @return
   *   A serialized string in JSON format suitable for the import() method.
   */
  public function export($entity, $prefix = '') {
    $vars = get_object_vars($entity);
    unset($vars['is_new']);
    return entity_var_json_export($vars, $prefix);
  }

The JSON code doesn't seem to generate the field_collection field settings in the database correctly when I run drush features-revert, however. These are the settings that live in the data column of the table field_config_instance.

I also see that there is a EntityDefaultFeaturesController::export() method in the Entity API module, which I believe is used for exporting entities themselves to Features code. The issue here is that the default settings for field_collection fields that are attached to nodes use the JSON generated by EntityAPIController::export(), which doesn't seem to capture everything needed.

I'm wondering if this is really an issue with EntityAPIController::export() and perhaps this issue should be moved to the entity module queue...I am not familiar enough, yet, with the purpose of that method and its accompanying EntityAPIController::import() method to know for sure if that is where the change should occur.

Thoughts everyone?

zorroposada’s picture

I used this patch; it worked fine for exporting a feature that contained a content type with a field collection in it.

But, I started having troubles when I exported other features that contained nodequeues. So, I changed it a bit so that the JSON code doesn't get included.

if ($output{0} == '{') {
  $output = '(object) ' . var_export(drupal_json_decode($output), TRUE);
}
pwaterz’s picture

+1 to #46

mr.york’s picture

Status: Needs work » Needs review
FileSize
582 bytes

patch

czigor’s picture

Patch #48 works for field collections, thanks!

danmuzyka’s picture

I will try this again to verify when I have time, but I believe my patch still doesn't solve the underlying issue, because if you have a field collection with customized default settings, and you export it to a feature and then later run a features-revert, the field collection settings get messed up in the field_config_instance table because they no longer reflect the correct PHP class (they are converted to stdClass).

This patch is really just a bandaid...I more complete solution is needed. I'm going to try to look for a better solution as soon as I can make some time to do so....

Macronomicus’s picture

Thanks #48 does mostly fix it, at least there is no wsod after enabling the feature now, still its like you said, seems some field settings didnt all carry over.

czigor’s picture

Status: Needs review » Needs work

OK, as its name suggests #48 does not really fix it. I had to manually set the default_value of the field collection to an empty array:

    'field_instance' => array(
      'bundle' => 'student',
      'default_value' => array(
      ),
David_Rothstein’s picture

Title: Features should reliably wrap JSON strings with quotes in exported Feature packages » Exporting a Field Collection field with a default value to Features leads to a PHP parse error
Project: Features » Field collection
Priority: Normal » Major
Status: Needs work » Needs review
FileSize
1.01 KB

I spent a while looking into this issue, and I think @danmuzyka has the right idea here (e.g. in #45).

The Features module's export format is PHP, not JSON. It's therefore not its job to try to detect JSON (or any other type of data) and convert it into PHP. Rather, if a module is overriding Features' export method, it's the module's job to make sure that valid PHP is produced in the end. (For an example of a module that does that correctly, converting its own native JSON format into PHP for a Features export, have a look at Rules.)

The proof of this is that even if Features were changed to look for JSON, that still wouldn't fix the fact that the exported field collection object is the wrong class (see #42) or that putting JSON in the {field_config_instance} table still won't actually work (i.e., the default value will not take effect) because that's not how Drupal normally stores things.

The problem here might actually be a name clash; Features assumes it can call $object->export() when a feature is being exported, but the Entity module uses the export() method for something else, namely direct JSON-based exports via the user interface. So it seems like it might just be called accidentally here. Maybe the ultimate correct solution is for one of those modules to change its API?

In the meantime, since Field Collection entities are not exportable via the UI anyway, but are exportable via Features when they are attached as a field somewhere else, it might make sense for Field Collection to simply override Entity here and use the export() method the way Features expects it to. That's what I did in the attached patch; it's not really an ideal solution, but it does work for the time being.

hefox’s picture

I think either features either a way to detect whether the export method is valid and use it (else not use that function and export as it would if that method didn't exist), else entities provide a way to return valid PHP; opened #1566104: Provide a method to return PHP from export method along that line.

David_Rothstein’s picture

If there were a way to detect whether an export method is valid, then that (combined with #1437264: features_var_export is converting custom class objects to arrays if don't have export method) does seem like it would solve this issue... but also seems like it would be tricky to do that detection?

hefox’s picture

Would likely have to

  • add a method or property export_type()
  • have methods take in a return type (php, json)
  • add a whitelist of valid classes
  • adda blacklist of invalid classes
emptyvoid’s picture

The #53 patch does indeed fix the object for the features index can properly render and the feature will validate. However, how I get the following on every page of the site.

Warning: class_implements(): object or string expected in entity_import() (line 304 of /code/sites/all/modules/contrib/entity/entity.module). Backtrace:

class_implements(NULL) entity.module:304
entity_import('FieldCollectionItemEntity', '{
            "item_id" : null,
            "field_name" : "field_member_cert_programs",
            "field_member_program" : { "und" : [] },
            "field_member_program_status" : { "und" : [ { "value" : "New Applicant" } ] },
            "field_member_program_state_date" : { "und" : [
                {
                  "value" : "1336460400",
                  "show_todate" : true,
                  "timezone" : "America\/Los_Angeles",
                  "offset" : -25200,
                  "offset2" : -25200,
                  "value2" : "1336460400"
                }
              ]
            }
          }') features.export.inc(607) : eval()'d code:867
eval() features.export.inc:607
features_get_normal('field', 'base_member_directory', ) features.export.inc:538
features_get_signature('normal', 'base_member_directory', 'field', ) features.export.inc:750
features_get_component_states(Array, 1, ) features.module:780
_features_restore('rebuild', Array) features.module:818
features_rebuild() features.admin.inc:325
features_admin_form(Array, Array) 
call_user_func_array('features_admin_form', Array) form.inc:787
drupal_retrieve_form('features_admin_form', Array) form.inc:331
drupal_build_form('features_admin_form', Array) form.inc:123
drupal_get_form('features_admin_form') 
call_user_func_array('drupal_get_form', Array) menu.inc:517
menu_execute_active_handler() index.php:21

emptyvoid’s picture

30equals’s picture

just applied patch from #53, and i got no parsing error anymore, nor do i have the problem mentioned in #57.

30equals’s picture

update: when i enabled my exported feature (after the patch) with drush, i got the following drush error:

class_implements(): object or string expected entity.module:304 [warning]
in_array() expects parameter 2 to be array, boolean given [warning]
entity.module:304

#304 in the entity.module file is part of the entity_import function, so i guess it's related to this issue..?

marvil07’s picture

+++ b/field_collection.module
@@ -365,6 +365,23 @@ class FieldCollectionItemEntity extends Entity {
+    $export = "entity_import('" . get_class($this) . "', '";

This is the patch from comment 53, but it uses the entity type instead of a class name, which is what entity_import() expects.

estrejlau’s picture

I'm getting the following error after applying the above patch: "Strict warning: Declaration of FieldCollectionItemEntity::export() should be compatible with that of Entity::export() in include_once() (line 100 of [...]/sites/all/modules/contrib/field_collection/field_collection.module)." Any ideas?

agentrickard’s picture

Make sure the arguments passed to the method are the same in both implementations and then update the patch.

estrejlau’s picture

Thanks agentrickard.

kenorb’s picture

The same problem here.

slucero’s picture

The patch in #64 has worked well for me and fixed the issue in all my test cases.

pwaterz’s picture

I am having an issue after patch 64. After Collection field is featurized i get an error with no message when i try to edit the field settings.

pwaterz’s picture

I was able to get it working by completely recreating the feature.

tim.plunkett’s picture

Assigned: Unassigned » tim.plunkett

Assigning for review tomorrow/this weekend.

tim.plunkett’s picture

Status: Needs review » Fixed

I was able to test this and it worked wonderfully. Thanks to bradjones1, ygerasimov, pwaterz, danmuzyka, mr.york, David_Rothstein, marvil07, eroepken and everyone else!

http://drupalcode.org/project/field_collection.git/commit/92a68e3

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Amber Himes Matz’s picture

What exactly is "fixed?" Or what are the steps necessary to implement this fix? I have updated field_collection to the June 8 dev and recreated my features. Still getting errors.

Recoverable fatal error: Argument 1 passed to field_collection_item_is_empty() must be an instance of FieldCollectionItemEntity, instance of stdClass given, called in /mysite/sites/all/modules/contrib/field_collection/field_collection.module on line 1271 and defined in field_collection_item_is_empty() (line 693 of /mysite/sites/all/modules/contrib/field_collection/field_collection.module).

and

EntityMalformedException: Missing bundle property on entity of type field_collection_item. in entity_extract_ids()
(line 7539 of /mysite/includes/common.inc).

Update: Through some serious blunt force, mashing of keyboard, and tapping my heels three times, it is now working.