Currently, using the services module, if I have a field collection implemented on a node, and I call a service to get all the data for that node, I get an xml portion like:

<field_collection_field_name_here>
<und is_array="true">
<item>
<value>1</value>
</item>
<item>
<value>2</value>
</item>
</und>
</field_collection_field_name_here>

where presumably those item -> values reference back to the various sub-values for the field collection.
when a page is displayed, these values are resolved.
I'm wondering what would be involved in resolving those values, say, when node_load is called on the host entity (that's the entity that contains the field collection (which is itself an entity, right), if that would be appropriate? Because that seems to be where services needs it.

I know this is a bit vague, but that's where I'm at.

Any ideas?

Comments

donundeen’s picture

oh dang, the xml was corrupted:

<field_collection_field_name_here>
<und is_array="true">
<item>
<value>1</value>
</item><item>
<value>2</value>
</item>
</und>
</field_collection_field_name_here>
donundeen’s picture

Or alternatively, if someone could give me some insight into HOW the data in the field collections is expanded within the hostentity,
then perhaps the modifications could be made on the services side, which may be more appropriate.

fago’s picture

You can try using the restws module, what should work as field-collection has working entity property integration (see rules-test cases).

Anyway, I think the service should function as the underlying API - treat field-collections as separate entities.

Wassim Ghannoum’s picture

I tried RESTful web services Module but i can't get the Json file

if i go to http://localhost/testingservices/field-collection/field-orders/1.json i will get the first value of the field collection in an html view and not in JSON format

other entities like user and node are working so i can get a JSON file from http://localhost/testingservices/node/1.json

Appreciate your help

Wassim Ghannoum’s picture

Status: Active » Fixed

i Think it is working now:

using this format, http://localhost/testingservices/field_collection_item/3.json

paul kim consulting’s picture

A few issues with just pointing people to restws:

- restws is incompatible with UUID, which is necessary when exporting to different drupal environments.
- The deploy module is heavily dependent on services. Deploying entities with field collections do not work.
- If a site is dependent on services, there is no reason for it to migrate to restws, and break it's api.

paul kim consulting’s picture

Cross referenced here: http://drupal.org/node/1621396

Status: Fixed » Closed (fixed)

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

star-szr’s picture

Status: Closed (fixed) » Active

Let's keep this open, still a valid feature request I think.

hypertext200’s picture

This may help. This can be easily achieve like 1621396#3 example and I'm looking forward to create a patch for field_collection module.

hypertext200’s picture

Status: Active » Needs review
StatusFileSize
new1.32 KB

Here is the patch which implements Services module hook. The XML or JSON should contain wrapper element <fieldcollection> as below.

field_collection_item_field['und'][0]['fieldcollection'] = array(ITEMS);

<!-- field collection starts here -->
<field_collection_item_field>
   <und is_array="TRUE">
      <item>
         <fieldcollection>
            <field_name>field_collection_item</field_name>
            <field_text>
               <und is_array="TRUE">
                  <item>
                     <value>Some text</value>
                  </item>
               </und>
            </field_text_unlimited>
            <field_text>
               <und is_array="TRUE">
                  <item>
                     <value>Some text</value>
                  </item>
               </und>
            </field_text_unlimited>
      </fieldcollection></item>
   </und>
</field_collection_item_field>
darrenmothersele’s picture

In addition to comment #6 I'll point people toward this issue http://drupal.org/node/1817956

Deploying entities relies on services. Deploying entities with Field collections is not currently possible.

Entity dependency module defines a dependency between entities with field collections and the actual field collection item entities.

Deploying these entities attempts to deploy the dependencies first. This fails because there is no service resource to receive them. I defined a simple service to do this, then uuid_services takes over and does it's stuff - but it fails because saving a field collection entity requires it's host entity. Obviously the host entity is not available yet, because the field collection item is deployed first due to the entity_dependency.

gumdal’s picture

Hi,

I have applied your patch. After applying the patch, I have triggered a test webservice request and I dont see any change in my webservice response. I again get the same response like this:

This is the part of XML response which am still getting the same after applying your patch:

.
.
.
<field_snake_photographs>
<und is_array="true">
<item>
<value>2</value>
</item>
<item>
<value>3</value>
</item>
</und>
</field_snake_photographs>
.
.
.

What I am trying to get is the contents of fields collection right inside the

"field_snake_photographs"

tag's contents instead of the value 2 & 3. What else am I supposed to do?

Thanks,
Raj Pawan G

gumdal’s picture

Any updates about the issue? I am badly in need of a fix for this, am not a PHP programmer and so need help. Thank you.

gumdal’s picture

Status: Needs review » Needs work

This patch (#11) unfortunately did not work for me as expected. Please check my below response on 25th Nov. I did not know then to change the status.

Thank you.

stupiddingo’s picture

+++ b/field_collection.module
@@ -1508,3 +1508,34 @@ function field_collection_devel_generate($object, $field, $instance, $bundle) {
+    $entities = _service_fieldcollection_recursive_search($arg, 'fieldcollection');

Using the latest releases of services and field_collection when calling /myrestserver/node/1 $arg holds the nid, not an array so when passed to _service_fieldcollection_recursive_search it fails.

What array should be passed to _service_fieldcollection_recursive_search?

gumdal’s picture

Using the concept from #11 and the Entity loading concept, I could pull the field collection information into the node XML (or JSON) in the webservices, I am using the latest beta 5 7.x-1.0 source. The modification done is not in a conventional way which would serve general purpose, I had to hardcode the field names in my code which I will explain later why I did it so.

First thing, had to implement the hook field_collection_services_request_postprocess_alter() instead of field_collection_services_request_preprocess_alter() as used by heshan.lk probably coz the way function calls work in services 3.0 is changed. I could observe that preprocess never get triggered here. Next, as mentioned by #16 there is an extra parameter now $options which actually holds the value instead of $args. Also, now we get the object collection in $options variable as stdClass, we need to convert it to array in order to enumerate through it.

function field_collection_services_request_postprocess_alter($controller, &$args, &$options) {
    $options = objectToArray($options);
        foreach ($options as $key => $arg)
        {
            // Testing it!
            $flattenedEntitiesObject = recursively_flatten_entities($arg);
            $options[$key] = $flattenedEntitiesObject;
        }
}

Next is a function which recursively checks in each of the element (and its children) if there is an entity (which is what field_collection is represented with). A recursive method is written which loads the entity and pulls out the entity information to prepare the field collection information into main node. I had to hardcode my field names here because once the entity is loaded, I could see many entity specific fields along with them is the user defined fields too. But none of those entity fields had information about what is the user defined field name with which entity is associated with. I would like to know if there is a way to identify the user defined field name so that I could provide a generalized solution for it and perhaps we can provide a patch to this.

function recursively_flatten_entities($options)
{
    $resultFlattenedArray = array();
    if (is_array($options))
    {
        $possibleCollection = $options;
        if ($possibleCollection['value']!=NULL && $possibleCollection['revision_id']!=NULL)
        {
            // Raj: Now this is bound to be a field_collection item - If it has only two values 'value' and 'revision_id' - ASSUMPTION!
                $valueID = $possibleCollection['value'];
                $valueLoadedEntity = entity_load ('field_collection_item', array($valueID));
                if (NULL!=$valueLoadedEntity)
                {
                    $theEntity = $valueLoadedEntity[$valueID];
                    if (NULL!=$theEntity)
                    {
                        // Raj: At this point, in entity, there is no way to identify the internal field name which was used in the field collection. Hence, I am hardcoding the collection field names since I know the corresponding field name.
                        // TODO: Find a solid fix for this later!
                        $theEntityArray = objectToArray($theEntity);
                        $sciName = $theEntityArray['field_coll_sci_name'];
                        $sciNameDescriber = $theEntityArray['field_coll_sci_describer'];
                        $scientificResults = array();
                        if (NULL!=$sciName)
                        {
                            $scientificResults['field_coll_sci_name'] = $sciName;
                        }
                        if (NULL!=$sciNameDescriber)
                        {
                            $scientificResults['field_coll_sci_describer'] = $sciNameDescriber;
                        }
                        if (!empty($scientificResults))
                        {
                            $resultFlattenedArray = array_merge($resultFlattenedArray, $scientificResults);
                        }

                        // For picture now:
                        $picture = $theEntityArray['field_coll_pic'];
                        $pictureCaption = $theEntityArray['field_field_coll_pic_caption'];
                        $picturePhotographer = $theEntityArray['field_field_coll_pic_fotographer'];
                        $photographArray = array();
                        if (NULL!=$picture)
                        {
                            $photographArray['field_coll_pic'] = $picture;
                            $photographArray['field_field_coll_pic_caption'] = $pictureCaption;
                            $photographArray['field_field_coll_pic_fotographer'] = $picturePhotographer;
                        }
                        if (!empty($photographArray))
                        {
                            $resultFlattenedArray = array_merge($resultFlattenedArray, $photographArray);
                        }
                    }
                }
        }
        else
        {
            foreach ($options as $key => $child)
            {
                $returnedResult = recursively_flatten_entities($child);
                //$resultFlattenedArray = array_merge($resultFlattenedArray,$returnedResult);
                //array_push($resultFlattenedArray,$returnedResult);
                $resultFlattenedArray[$key] = $returnedResult;
            }
        }
    }
    else
    {
        return $options;
    }
    return $resultFlattenedArray;
}

Next is a small helper method to convert object collection into array:

function objectToArray($d) {
    // Raj: http://www.if-not-true-then-false.com/2009/php-tip-convert-stdclass-object-to-multidimensional-array-and-convert-multidimensional-array-to-stdclass-object/
    if (is_object($d)) {
        // Gets the properties of the given object
        // with get_object_vars function
        $d = get_object_vars($d);
    }

    if (is_array($d)) {
        /*
        * Return array converted to object
        * Using __FUNCTION__ (Magic constant)
        * for recursive call
        */
        return array_map(__FUNCTION__, $d);
    }
    else {
        // Return array
        return $d;
    }
}

Please observe that the $theNode is not used but I think there is a dependency on usage of entity_load() which needs the node to be loaded(?). Not sure about how it works but if I take out the call for node_load() the entity fetch seems to fail. I was wrong earlier, my test case about this failed earlier and now I could debug and confirm that there is no dependency as such between node_load() and entity_load(). I have updated the code too accordingly.

What I would like to do is to make it generalized so that we can give a good patch for it. I can confirm it works in my scenario with the field names specific to my case. However, I am concerned about the points mentioned in #6 and #12 which I could not pretty much understand. I would like experts to let me know if this approach is fine to load the entities and fetch field collection information.

Last but not the least, had to setup PHP debugging for Mac OS X. It was a first time experience for me and thought it would be best to archive the procedure: http://gumdal.blogspot.in/2013/09/setup-for-debugging-php-code-on.html

gumdal’s picture

Issue summary: View changes

Wrapping XML with code tags

shenzhuxi’s picture

Issue summary: View changes
Issue tags: +services
StatusFileSize
new1.9 KB

SInce has already done a good job, I added field_collections relationships to all the entity resources.

The last submitted patch, 11: 1180574-integration-with-services-11.patch, failed testing.