4

On node insert I want to save another node with data taken from first node into other Drupal database. The node in second site has 3 fields: title, image field, is_public. Both Drupal installation shares same files directories.

Code:

$node = new stdClass;
$node->type = GALLERY_IMAGE_TYPE;
node_object_prepare($node);
$node->is_new = True;
$node->language = LANGUAGE_NONE;
$node->title = $file->filename;
$node->uid = 1;
$node->status = 1;
$node->{GALLERY_IMAGE_FIELD_NAME}[LANGUAGE_NONE][] = array(
    'fid' => $file->fid,
    'alt' => $image['alt'],
    'title' => $image['title'],
);
$node->{GALLERY_IMAGE_PUBLIC_FIELD_NAME}[LANGUAGE_NONE][]['value'] = $is_public;
node_save($node);
db_set_active();

$node structure before node_save is similar to node structure created from admin panel and dump on hook_node_view:

Dump from hook_node_view in second database:

[field_file_image] => Array
    (
        [und] => Array
            (
                [0] => Array
                    (
                        [fid] => 9
                        [display] => 1
                        [description] => 
                        [upload_button] => Upload
                        [remove_button] => Remove
                        [upload] => 
                        [width] => 415
                        [height] => 332
                        [alt] => 
                        [title] => 
                    )

            )

    )

[field_file_image_is_public] => Array
    (
        [und] => Array
            (
                [0] => Array
                    (
                        [value] => 1
                    )

            )

    )

Node structure before node_save:

    stdClass Object
    (
        [type] => image
        [status] => 1
        [promote] => 1
        [sticky] => 0
        [uid] => 1
        [created] => 1355514057
        [revision] => 
        [comment] => 2
        [menu] => Array
            (
                [link_title] => 
                [mlid] => 0
                [plid] => 0
                [menu_name] => main-menu
                [weight] => 0
                [options] => Array
                    (
                    )

                [module] => menu
                [expanded] => 0
                [hidden] => 0
                [has_children] => 0
                [customized] => 0
                [parent_depth_limit] => 8
            )

        [language] => und
        [title] => wyoming-rocky-mountains.jpg
        [field_file_image] => Array
            (
                [und] => Array
                    (
                        [0] => Array
                            (
                                [fid] => 13
                                [display] => 1
                                [description] => 
                                [upload_button] => Upload
                                [remove_button] => Remove
                                [upload] => 
                                [width] => 415
                                [height] => 332
                                [alt] => 
                                [title] => 
                            )

                    )

            )

        [field_file_image_is_public] => Array
            (
                [und] => Array
                    (
                        [0] => Array
                            (
                                [value] => 1
                            )

                    )

            )

    )


$node structure after node_save:


stdClass Object
(
    [vid] => 13
    [uid] => 1
    [title] => wyoming-rocky-mountains.jpg
    [log] => 
    [status] => 1
    [comment] => 2
    [promote] => 1
    [sticky] => 0
    [nid] => 13
    [type] => image
    [language] => und
    [created] => 1355514057
    [changed] => 1355514057
    [tnid] => 0
    [translate] => 0
    [revision_timestamp] => 1355514057
    [revision_uid] => 1
    [rdf_mapping] => Array
        (
            [rdftype] => Array
                (
                    [0] => sioc:Item
                    [1] => foaf:Document
                )

            [title] => Array
                (
                    [predicates] => Array
                        (
                            [0] => dc:title
                        )

                )

            [created] => Array
                (
                    [predicates] => Array
                        (
                            [0] => dc:date
                            [1] => dc:created
                        )

                    [datatype] => xsd:dateTime
                    [callback] => date_iso8601
                )

            [changed] => Array
                (
                    [predicates] => Array
                        (
                            [0] => dc:modified
                        )

                    [datatype] => xsd:dateTime
                    [callback] => date_iso8601
                )

            [body] => Array
                (
                    [predicates] => Array
                        (
                            [0] => content:encoded
                        )

                )

            [uid] => Array
                (
                    [predicates] => Array
                        (
                            [0] => sioc:has_creator
                        )

                    [type] => rel
                )

            [name] => Array
                (
                    [predicates] => Array
                        (
                            [0] => foaf:name
                        )

                )

            [comment_count] => Array
                (
                    [predicates] => Array
                        (
                            [0] => sioc:num_replies
                        )

                    [datatype] => xsd:integer
                )

            [last_activity] => Array
                (
                    [predicates] => Array
                        (
                            [0] => sioc:last_activity_date
                        )

                    [datatype] => xsd:dateTime
                    [callback] => date_iso8601
                )

        )

    [cid] => 0
    [last_comment_timestamp] => 1355514057
    [last_comment_name] => 
    [last_comment_uid] => 1
    [comment_count] => 0
    [name] => admin
    [picture] => 0
    [data] => b:0;
)

I don't understand why custom fields are wipeout.

EDIT

Anyway I switched from node type to entity. The issue still present. I put test code to Drupal installation which is using database called 'gallery':

$e = entity_create('model', array('type' => 'image'));
$ew = entity_metadata_wrapper('model',$e);
$ew->field_entity_image_is_public->set(1);
$ew->field_entity_image->set(array(
    'fid' => 12,
    'alt' => 'alt',
    'title' => 'title',
));
$ew->field_entity_image_name->set('image name');
$ew->save();

It works ok, but when I try to use similar snipper in other installation:

$file = file_load($image['fid']);
unset($file->fid);
$file->uid = 1;
db_set_active('gallery');
file_save($file);
$e = entity_create('model', array('type' => 'image'));
$ew = entity_metadata_wrapper('model',$e);
$ew->field_entity_image_is_public->set(1);
$ew->field_entity_image->set(array(
    'fid' => $file->fid,
    'alt' => $image['alt'],
    'title' => $image['title'],
));
$ew->field_entity_image_name->set($file->filename);
$ew->save();
db_set_active();

Custom fields are not stored. Only record in file_managed table is inserted correctly.

All Drupal installations are on the same server so I thought that I can just switch to other installation database, but now I start thinking about using somekind of web service but it is pointless in this case :/

  • i think that in the first snippet you are setting the image to the is_public insted of image var ? (image looks like unused) – mojzis Dec 14 '12 at 22:33
  • @mojzis That is true. Still, that doesn't explain why the node object contains the image field before being passed to node_save(), and not after. – kiamlaluno Dec 14 '12 at 22:53
  • @kiamlaluno it does indeed, because he sets it to 1 (true), but it's supposed to be an array if i rememeber well - so it doesn't get saved ... – mojzis Dec 14 '12 at 23:38
  • @mojzis $is_public is 1 or 0, it's checbokx on/off field – Codium Dec 16 '12 at 9:25
  • @drupality on line 14 (the longest) of your 1st snippet, you assign $is_public to the image field, instead of the $image variable. thats why it is set before saving, but is not set after saving - the field module knows it's not an image ... – mojzis Dec 16 '12 at 9:45
4

The quick answer is this - Do a field_info_cache_clear() call just before you flip the database and the fields for the node should be set correctly in the target site as well i.e.

field_info_cache_clear();
db_set_active('other');
module_list(TRUE); // optional, if the two sites have different sets of modules enabled..
// Do your stuff here..
db_set_active('default');

Having said that, let us try to understand the fundamental problem here and why I think it is a bad idea to be doing this in the first place. The problem is static caching.

Two different Drupal sites may be different from each other in numerous ways - different set of active modules, themes and entities, different set of fields attached to content types with the same name, different values for variables (configuration) and so on. These differences typically lie in the respective databases that the sites connect to.

Now, when we we flip the database using db_set_active() in the middle of the page request, our assumption is that all future method calls will be against the other database. However, this is not entirely true. We forget that a lot of getter methods statically cache data fetched from the database during Drupal bootstrap. Examples include module_list(), entity_get_info(), module_implements(), _field_info_collate_types(), _field_info_collate_fields() and many more. As the bootstrap phase has already passed by the time you flip the database, these static caches of these methods will not be cleared by Drupal automatically and is the responsibility of the developer to do so before flipping.

Not only is it not practical to lookup all methods that statically cache data and are called just before you flip the database, but some of them don't use the drupal_static() global store for cached data as well making it tougher to clear their caches elegantly. Now, add contributed modules to the mix and your application becomes extremely unreliable and super hard to debug. The only way you can circumvent this reliably is by bootstrapping the target site also. However, this is both expensive and assumes that both sites are running off the same code-base. (Drupal multi-site)

So, one has to be super careful while flipping the database when a page is being served. I would recommend not making any module/theme API calls and sticking just to the core Database API to simply read/write to/lookup. For your use case, one way I can think of, is to dump information about the node to be created from the source database to a temporary table in the target database and set off a trigger in the target site to fetch entries from that table and create nodes from them locally.

  • Thanks for this great explanation, I'm already using other solution – Codium Dec 19 '12 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.