I am trying to flag a node in code, and then set the flagging field values.

One method is to use $flag->flag followed by flag_get_entity_flags() with a foreach to iterate through all the results, find the flag id you just created, load it with entity_load, set the field value, wrap it with entity_metadata_wrapper, and then save it.

Another method would be to create the flagging with entity_create, wrap it with entity_metadata_wrapper, and then set the field value directly. It's much cleaner this way. However, entity_create() is returning 0 when I try to create a flagging, and I'm not sure what's going on. Is there something incorrect in my $flag_settings?

        $flag_settings = array(
          'fid' => 1,
          'entity_type' => 'node',
          'entity_id' => 4646,
          'uid' => 1,
          'sid' => 0,
        );

        $flag = entity_create('flagging', $flag_settings);
        // at this point, $flag equal 0 because entity_create fails.

        $flag_wrapper = entity_metadata_wrapper('flagging', $flag);
        $flag_wrapper->field_myfield = 'myvalue';
        //fails because entity_create failed, not sure if EMW works for flaggings
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

micromegas’s picture

Issue summary: View changes
micromegas’s picture

Title: Flags and entity_create, entity_metadata_wrapper » Flags and entity_create
Issue summary: View changes

removed EMW info, since I confirmed that flags are working with EMW. Still can't get entity_create to work, however.

joachim’s picture

Title: Flags and entity_create » Add support for entity_create() to flaggings
Category: Support request » Feature request

entity_create() returns FALSE for a flagging entity because:

- the flagging entity type has no creation callback defined
- the flagging entity type is not using a controller that implements the entity API interface

(see http://drupalcontrib.org/api/drupal/contributions!entity!entity.module/f...)

I've already made the decision that we shouldn't add a dependency on Entity API, so that leaves us with the create callback. I'd be fine with that being added, since if Entity API isn't present, nothing will mind.

If you feel like tackling a patch, it should be fine to crib from EntityAPIController::create(). There's not much involved.

What you shouldn't do with the $flagging entity is use entity_save() on it, because that will bypass the flagging API.

You should instead do:

$flag = flag_get_flag('your_flag_name');
$flag->flag('flag', $node->nid, NULL, FALSE, $flagging);

That will take the $flagging as the starting point for the new flagging.

If you can get that to work, could you update https://drupal.org/node/1748148#write-flagging-fields, since, as you say, it's a cleaner approach than performing the flagging then having to go hunting for it.

micromegas’s picture

I see; the correct workflow would be create the flag with entity_create(), pass it to the flag->flag() method to save it, then change the field values, and then use entity_save()/EMW->save()... hence the need for an entity_create() callback.

joachim’s picture

You shouldn't use entity_save().

The workflow should be:

$values = array(...);
$flagging = entity_create('flagging', $values);
$flag = flag_get_flag('your_flag_name');
$flag->flag('flag', $node->nid, NULL, FALSE, $flagging);

The call to $flag->flag() saves the flagging entities as part of the process.

micromegas’s picture

Isn't entity_metadata_wrapper/entity_save() needed to set/save the flagging field values, after the initial flagging entity is created and saved?

So, in other words, don't use entity_save to create the flag; only use it to save field values on a flag that was already created/saved with $flag->flag. Is this correct? Or is there some way to save field values directly with $flag->flag?

I've got a simple entity_create() callback working and I'll post the patch when it's finished.

joachim’s picture

The flag API takes care of saving the flagging, which in turn saves the field values.

This code works for me:

  $flag_name = 'test_2162393';
  $nid = 7;
  $field_name = 'field_test_2162393';
  
  // Create a new flagging object.
  $values = array(
    'flag_name' => $flag_name,
  );
  $flagging = (object) $values;

  // Set field values using one of the following methods:
  // Either: A, with Entity API.
  $flagging->{$field_name}['und'][0]['value'] = 'foo';

  // Or B, directly:
  $flagging_wrapper = entity_metadata_wrapper('flagging', $flagging);
  $flagging_wrapper->{$field_name}->set('some text!');
  
  // Invoke the Flag API to set the flagging. This also saves the flagging entity.
  $flag = flag_get_flag($flag_name);
  $flag->flag('flag', $nid, NULL, FALSE, $flagging);
  dsm($flagging);

Having an entity_create callback would only change the ' $flagging = (object) $values;' line, which isn't much, but it does contribute towards a consistent DX which is a good thing.

joachim’s picture

BTW, https://drupal.org/node/1748148#write-flagging-fields will need updating after this.

micromegas’s picture

Status: Active » Needs review
FileSize
1.56 KB

Added patch for entity_create() callback. Note that it also allows you to specify an fid to keep it consistent with other entity_create() callbacks.

joachim’s picture

Status: Needs review » Needs work

Thanks for the patch. I like the approach of allowing either the flag name or the fid.

Just a few things that need a tidy-up:

  1. +++ b/flag.module
    @@ -73,6 +74,35 @@ function flagging_load($flagging_id, $reset = FALSE) {
    + *   An object array containing the property values
    

    It's either an object or an array, not both ;) I'd say instead 'An unsaved Flagging object containing the property values.' There's a missing full stop too.

  2. +++ b/flag.module
    @@ -73,6 +74,35 @@ function flagging_load($flagging_id, $reset = FALSE) {
    +  if (!array_key_exists('flag_name', $values)) {
    

    isset() is easier to read than array_key_exists(); it's also marginally quicker.

  3. +++ b/flag.module
    @@ -73,6 +74,35 @@ function flagging_load($flagging_id, $reset = FALSE) {
    +      // add flag_name, determined from fid
    

    Comments need to be written as full sentences. This needs a capital and a full stop.

Also, I'm not entirely sure when it comes to referencing methods, but $flag::flag() seems a bit of a mixed case to me. flag_flag::flag() identifies the class; $flag->flag() is an example of the typical variable you'd have. I'm ok with whichever you think it clearer.

micromegas’s picture

Assigned: Unassigned » micromegas
Status: Needs work » Needs review
FileSize
1.55 KB

Attached patch: fixed comment weirdness and changed to isset().

Status: Needs review » Needs work

The last submitted patch, 11: flag-entity_create_callback-2162393-11.patch, failed testing.

micromegas’s picture

Status: Needs work » Needs review
FileSize
1.55 KB

Patch was wonky, made a new one.

shabana.navas’s picture

Status: Needs review » Reviewed & tested by the community

The patch works perfectly. My example:

  $values = array(
    'fid' => 10,
    'entity_type' => 'flagging',
    'entity_id' => 2,
    'uid' => 1,
    'sid' => 0,
  );
  $flagging = entity_create('flagging', $values);

  $flagging_wrapper = entity_metadata_wrapper('flagging', $flagging);
  dpm($flagging_wrapper);
  //This is where I am entering the value for my field
  $flagging_wrapper->field_something->set('I just entered something!');

  $flag = flag_get_flag('bookmarks');
  $flag->flag('flag', 61, NULL, FALSE, $flagging);

  dpm($flagging);

I now have a record in field_something for this flagging entity type.

joachim’s picture

Status: Reviewed & tested by the community » Fixed

That's great.

I've fixed the whitespace and tweaked the comments a bit to say that this is an Entity API callback

git commit -m "Issue #2162393 by micromegas: Added support for entity_create() to flaggings." --author="micromegas "

micromegas’s picture

joachim’s picture

That's super, thanks!

Status: Fixed » Closed (fixed)

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