Using rules to populate a field with the output of pdfprevew I have a field (public_files) that accepts file uploads to which I have applied the pdfpreview module which provides a field formatter that will provide the generated image for pdf files.  I have another field for cover images.

This setup is working well, and I basically default to the cover image field, and fallback to the pdf preview version of the first file if the cover image hasn't been provided.  A problem arises for a section of the site where I only want to list items that have cover images.  There is a complicated bug in drupal that prevents me from doing the filtering in views to only items that have a cover image or for which the first file is a pdf file.

To alleviate this, what I'd like to do is use rules to automatically populate the cover image field with the generated cover whenever there is a generated cover image, and the cover image field is empty.

Sorry for the long preamble, here is the question:

Is there any way to get at the pdf preview image and populate an image field with it in rules?
From your question, I seem to understand that this is your goal (= quote from your question):


  ... use rules to automatically populate the cover image field with the generated cover whenever there is a generated cover image, and the cover image field is empty.


There seem to be at least 3 ways to achieve that goal, as further detailed below ...

Solution 1

This solution elaborates on one of your comments, which is like so:


  I was thinking at node view, might be a good time just to be sure that the preview had had a chance to be saved. I'd then need a condition to check whether the cover field already has a value and one to see if either there is a pdfpreview available or if the first file in the field is a pdf.


This could indeed work, but the crucial Rules challenge here is that there is no such event like "BEFORE" a node is being viewed. Because the "clue" about what Rules EVent "Content is viewed" actually means, seems to be like so:


The event Content is viewed is what it is: the user has (already) started viewing the content.
The (system) event Drupal is initializing is what you should use instead (possible combined with other Events and/or Actions), if you want to trigger some Rules "Action(s)" BEFORE the user can start viewing (= looking at) the content.


For more details, and a working sample (in Rules 'export format'), refer to
How to specify a Rules event like &quot;Content is &#39;going to be&#39; viewed&quot;?

My advice: only use this if all other options (solutions) fail. Read on for what IMO is a better solution.

Solution 2

This solution elaborates on one of your comments, which is like so:


  ...  at node create and node update may be a much better time, if pdf preview has had a chance to do what it does by the time those events fire ...


Using this approach, you'll run into another Rules challenge ... I.e what's detailed in issue # 430274, about an event which is a variation of your event here, and somehow explains that "after saving something" actually happens "before saving something". This is not a bug, but simply how the Rules module works.

My advice: using this solution is a kind of risky, because of that above mentioned Rules challenge. Read on for what IMO is a better solution.

Solution 3

A possible compromise to avoid the kind of issues described in Solution 2, is to implement what needs to be done into a Rules Component, so that your original Rule "schedules the execution" (using the Rules Scheduler sub-module) of that Rules component. For example after only a few seconds or minutes if your cron job runs frequent enough (otherwise it'll be next time cron runs). This compromise will ensure that, at the time the Rules component is executed, the entity is for sure saved (so that can't be the reason anymore then why things don't work as expected). Read on for how you can get this to work ...

Step 1 - Create a Rules Component

Have a look at this Rules Component, in Rules export format:

{ "rules_populate_an_output_field_with_an_input_field" : {
    "LABEL" : "Populate an output field with an input field",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "USES VARIABLES" : { "node_to_update" : { "label" : "Node to be updated", "type" : "node" } },
    "IF" : [
      { "entity_has_field" : { "entity" : [ "node-to-update" ], "field" : "field_image" } },
      { "NOT data_is_empty" : { "data" : [ "node-to-update:field-image" ] } },
      { "entity_has_field" : { "entity" : [ "node-to-update" ], "field" : "field_cover_image" } },
      { "data_is_empty" : { "data" : [ "node-to-update:field-cover-image" ] } }
    ],
    "DO" : [
      { "data_set" : {
          "data" : [ "node-to-update:field-cover-image" ],
          "value" : [ "node-to-update:field-image" ]
        }
      },
      { "entity_save" : { "data" : [ "node-to-update" ], "immediate" : "1" } }
    ]
  }
}


This Rules Component used a "node" (the node to be updated) as a parameter.

This is what the Rules Conditions in the above Rules Component are about:


It uses a parameter "Node to be updated".
It processes the fields with machine names field_cover_image and  field_image (adapt the machine names to fit your own field names, prior to trying to import this Rules Component in your own site).
It has a rules condition "Entity has field" (twice) to make those fields available for subsequent processing.
It has a Rules Condition for each of both fields to check that their initial value (before the Rules Component's actions will be triggered), to match your requirement like "... populate the cover image field with the generated cover whenever there is a generated cover image, and the cover image field is empty...".


This is what the Rules Actions in the above Rules Component do:


Set the value of field field_cover_image equal to the value of field  field_image.
Save the node (to ensure the updated value actually gets saved ...).


Step 2 - Create a Rule to schedule the Rules Component

This one is pretty easy, here is a rule (in Rules export format) that will "schedule" the execution of the Rules Component from the previous step:

{ "rules_schedule_image_population" : {
    "LABEL" : "Schedule image population",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules", "rules_scheduler" ],
    "ON" : { "node_insert" : [], "node_update" : [] },
    "IF" : [
      { "entity_has_field" : { "entity" : [ "node" ], "field" : "field_cover_image" } }
    ],
    "DO" : [
      { "schedule" : {
          "component" : "rules_populate_an_output_field_with_an_input_field",
          "date" : "+1 min",
          "identifier" : "Schedule-image-population-[node:nid]",
          "param_node_to_update" : [ "node" ]
        }
      }
    ]
  }
}


The rule uses as Rules Event "After creating a new node", or "After updating an existing node".

To avoid wasting resources, we only want to trigger the Rules Action for nodes that do have that field_cover_image field we want to populate (hence the Rules Condition).

And all this rule has to do (as Rules Action), is to schedule the execution of the Rules Component from the previous step. Adapt the delay to fit your needs (I've set it to just 1 min).

My advice: go for solution 3 (tested in my own setup, works like a charm ...)

Easy, no?