1

I'm creating a custom JSON:API Resource to store push notifications tokens.

The user account field where the tokens are stored has a limit of 5 items.

I am using appendItem() to add the value to field.

However, if the field already has 5 values, then appendItem() does nothing. In this case, instead of doing nothing, I want to bump the first item (the value saved first) from the array and then move all the other values up a place (last in last out).

I can code this myself but it occurred to me that this may be something Drupal already provides but I just don't know enough about the API to figure out where to look for it. Does Drupal provide some way to handle multi-value field values when the limit on the number of values has been reached?

Here's my code so far:

// Make sure we have a real token.
if (strlen($push_token) >= 100) {

  // Generate an array of the existing token values.
  $existing_tokens = $current_user->get('field_text_token_push')->getValue();
  $token_values = [];
  foreach($existing_tokens as $existing_token) {
    $token_values[] = $existing_token['value'];
  }

  // Check whether the token already exists.
  if (in_array($push_token, $token_values)) {
    $this->loggerFactory->notice("Push token: Did not add token for UID @uid because it already exists.", [
      '@uid' => $uid,
    ]);
    $return_bool = TRUE;
  } else {
    // Add the token.
    // Todo: If we have reached the field limit, automatically remove the earliest value and replace with the new value.
    $current_user->get('field_text_token_push')->appendItem($push_token);
    $current_user->save();
    $this->loggerFactory->notice("Push token: Added token for UID @uid.", [
      '@uid' => $uid,
    ]);
    $return_bool = TRUE;
  }
}

2 Answers 2

2

Broken these down into separate lines to help you pick and choose what you need.

$field = $current_user->get('field_text_token_push');
$field_definition = $field->getFieldDefinition();
$field_storage_definition = $field_definition->getFieldStorageDefinition();

// Upper limit.
$cardinality = $field_storage_definition->getCardinality();

// Number of current items.
$items = $field->count();

I don't know about this but I suspect that there isn't anything or any method that will automatically handle your use case (e.g. FIFO for multi value fields). You will probably have to code it yourself with a combination of the above and...

I guess with this then you could $field->removeItem(0)->rekey() if you've reached the maximum cardinality. Obviously handling excluding count comparisons where the cardinality is FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED

2

It should be no problem to bump the first item with array_slice():

$values = $node->field_foo->getValue();
$values[] = ['value' => 'bar'];
$values = array_slice($values, -5);
$node->field_foo->setValue($values);
$node->save();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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