/**
  * {@inheritdoc}
  */
 protected function alterBuild(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode)
 {
     $entity_type_id = $entity->getEntityTypeId();
     if ($entity instanceof ContentEntityInterface && $entity->isDefaultRevision() || !$entity->getEntityType()->isRevisionable()) {
         $build['#contextual_links'][$entity_type_id] = ['route_parameters' => [$entity_type_id => $entity->id()]];
     } else {
         $build['#contextual_links'][$entity_type_id . '_revision'] = ['route_parameters' => [$entity_type_id => $entity->id(), $entity_type_id . '_revision' => $entity->getRevisionId()]];
     }
 }
 /**
  * Saves values of configurable fields for an entity.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity.
  * @param bool $update
  *   TRUE if the entity is being updated, FALSE if it is being inserted.
  */
 protected function saveFieldItems(EntityInterface $entity, $update = TRUE)
 {
     $vid = $entity->getRevisionId();
     $id = $entity->id();
     $bundle = $entity->bundle();
     $entity_type = $entity->getEntityTypeId();
     $default_langcode = $entity->getUntranslated()->language()->id;
     $translation_langcodes = array_keys($entity->getTranslationLanguages());
     if (!isset($vid)) {
         $vid = $id;
     }
     foreach ($this->entityManager->getFieldDefinitions($entity_type, $bundle) as $field_name => $field_definition) {
         $storage_definition = $field_definition->getFieldStorageDefinition();
         if (!$this->usesDedicatedTable($storage_definition)) {
             continue;
         }
         $table_name = static::_fieldTableName($storage_definition);
         $revision_name = static::_fieldRevisionTableName($storage_definition);
         // Delete and insert, rather than update, in case a value was added.
         if ($update) {
             // Only overwrite the field's base table if saving the default revision
             // of an entity.
             if ($entity->isDefaultRevision()) {
                 $this->database->delete($table_name)->condition('entity_id', $id)->execute();
             }
             $this->database->delete($revision_name)->condition('entity_id', $id)->condition('revision_id', $vid)->execute();
         }
         // Prepare the multi-insert query.
         $do_insert = FALSE;
         $columns = array('entity_id', 'revision_id', 'bundle', 'delta', 'langcode');
         foreach ($storage_definition->getColumns() as $column => $attributes) {
             $columns[] = static::_fieldColumnName($storage_definition, $column);
         }
         $query = $this->database->insert($table_name)->fields($columns);
         $revision_query = $this->database->insert($revision_name)->fields($columns);
         $langcodes = $field_definition->isTranslatable() ? $translation_langcodes : array($default_langcode);
         foreach ($langcodes as $langcode) {
             $delta_count = 0;
             $items = $entity->getTranslation($langcode)->get($field_name);
             $items->filterEmptyItems();
             foreach ($items as $delta => $item) {
                 // We now know we have someting to insert.
                 $do_insert = TRUE;
                 $record = array('entity_id' => $id, 'revision_id' => $vid, 'bundle' => $bundle, 'delta' => $delta, 'langcode' => $langcode);
                 foreach ($storage_definition->getColumns() as $column => $attributes) {
                     $column_name = static::_fieldColumnName($storage_definition, $column);
                     // Serialize the value if specified in the column schema.
                     $record[$column_name] = !empty($attributes['serialize']) ? serialize($item->{$column}) : $item->{$column};
                 }
                 $query->values($record);
                 $revision_query->values($record);
                 if ($storage_definition->getCardinality() != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && ++$delta_count == $storage_definition->getCardinality()) {
                     break;
                 }
             }
         }
         // Execute the query if we have values to insert.
         if ($do_insert) {
             // Only overwrite the field's base table if saving the default revision
             // of an entity.
             if ($entity->isDefaultRevision()) {
                 $query->execute();
             }
             $revision_query->execute();
         }
     }
 }
 /**
  * {@inheritdoc}
  */
 protected function doSave($id, EntityInterface $entity)
 {
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     if ($entity->isNew()) {
         // Ensure the entity is still seen as new after assigning it an id, while
         // storing its data.
         $entity->enforceIsNew();
         if ($this->entityType->isRevisionable()) {
             $entity->setNewRevision();
         }
         $return = SAVED_NEW;
     } else {
         // @todo Consider returning a different value when saving a non-default
         //   entity revision. See https://www.drupal.org/node/2509360.
         $return = $entity->isDefaultRevision() ? SAVED_UPDATED : FALSE;
     }
     $this->populateAffectedRevisionTranslations($entity);
     $this->doSaveFieldItems($entity);
     return $return;
 }
 /**
  * {@inheritdoc}
  *
  * @todo Revisit this logic with forward revisions in mind.
  */
 protected function doSave($id, EntityInterface $entity)
 {
     if ($entity->_rev->is_stub) {
         $entity->isDefaultRevision(TRUE);
     } else {
         // Enforce new revision if any module messed with it in a hook.
         $entity->setNewRevision();
         // Decide whether or not this is the default revision.
         if (!$entity->isNew()) {
             $default_rev = \Drupal::service('entity.index.rev.tree')->getDefaultRevision($entity->uuid());
             if ($entity->_rev->value == $default_rev) {
                 $entity->isDefaultRevision(TRUE);
             } else {
                 $entity->isDefaultRevision(FALSE);
             }
         }
     }
     return parent::doSave($id, $entity);
 }