You are here

class BrightcoveVideo in Brightcove Video Connect 3.x

Same name in this branch
  1. 3.x src/Entity/BrightcoveVideo.php \Drupal\brightcove\Entity\BrightcoveVideo
  2. 3.x modules/media_brightcove/src/Plugin/media/Source/BrightcoveVideo.php \Drupal\media_brightcove\Plugin\media\Source\BrightcoveVideo
  3. 3.x modules/media_entity_brightcove/src/Plugin/MediaEntity/Type/BrightcoveVideo.php \Drupal\media_entity_brightcove\Plugin\MediaEntity\Type\BrightcoveVideo
Same name and namespace in other branches
  1. 8.2 src/Entity/BrightcoveVideo.php \Drupal\brightcove\Entity\BrightcoveVideo
  2. 8 src/Entity/BrightcoveVideo.php \Drupal\brightcove\Entity\BrightcoveVideo

Defines the Brightcove Video entity.

Plugin annotation


@ContentEntityType(
  id = "brightcove_video",
  label = @Translation("Brightcove Video"),
  handlers = {
    "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
    "list_builder" = "Drupal\brightcove\BrightcoveVideoListBuilder",
    "views_data" = "Drupal\brightcove\Entity\BrightcoveVideoViewsData",

    "form" = {
      "default" = "Drupal\brightcove\Form\BrightcoveVideoForm",
      "add" = "Drupal\brightcove\Form\BrightcoveVideoForm",
      "edit" = "Drupal\brightcove\Form\BrightcoveVideoForm",
      "delete" = "Drupal\brightcove\Form\BrightcoveEntityDeleteForm",
    },
    "access" = "Drupal\brightcove\Access\BrightcoveVideoAccessControlHandler",
    "route_provider" = {
      "html" = "Drupal\brightcove\BrightcoveVideoHtmlRouteProvider",
    },
    "inline_form" = "Drupal\brightcove\Form\BrightcoveInlineForm",
  },
  base_table = "brightcove_video",
  admin_permission = "administer brightcove videos",
  entity_keys = {
    "id" = "bcvid",
    "label" = "name",
    "uuid" = "uuid",
    "uid" = "uid",
    "langcode" = "langcode",
    "status" = "status",
  },
  links = {
    "canonical" = "/brightcove_video/{brightcove_video}",
    "add-form" = "/brightcove_video/add",
    "edit-form" = "/brightcove_video/{brightcove_video}/edit",
    "delete-form" = "/brightcove_video/{brightcove_video}/delete",
    "collection" = "/admin/content/brightcove_video",
  },
  field_ui_base_route = "brightcove_video.settings"
)

Hierarchy

Expanded class hierarchy of BrightcoveVideo

7 files declare their use of BrightcoveVideo
brightcove.install in ./brightcove.install
Brightcove install file.
brightcove.module in ./brightcove.module
Brightcove module.
BrightcoveSubscriptionController.php in src/Controller/BrightcoveSubscriptionController.php
BrightcoveUtil.php in src/BrightcoveUtil.php
BrightcoveVideoController.php in src/Controller/BrightcoveVideoController.php

... See full list

File

src/Entity/BrightcoveVideo.php, line 75

Namespace

Drupal\brightcove\Entity
View source
class BrightcoveVideo extends BrightcoveVideoPlaylistCmsEntity implements BrightcoveVideoInterface {

  /**
   * Ingestion request object.
   *
   * @var \Brightcove\API\Request\IngestRequest
   */
  protected $ingestRequest = NULL;

  /**
   * Create or get an existing ingestion request object.
   *
   * @return \Brightcove\API\Request\IngestRequest
   *   Returns an ingestion request object.
   */
  protected function getIngestRequest() {
    if (is_null($this->ingestRequest)) {
      $this->ingestRequest = new IngestRequest();
    }
    return $this->ingestRequest;
  }

  /**
   * Helper function to provide default values for image fields.
   *
   * The original and the save entity's field arrays is a bit different from
   * each other, so provide the missing values.
   *
   * @param array &$values
   *   The field's values array.
   */
  protected function provideDefaultValuesForImageField(array &$values) {

    /** @var \Drupal\file\Entity\File $file */
    foreach ($values as $delta => &$value) {
      $file = File::load($value['target_id']);
      if (!is_null($file)) {
        $value += [
          'display' => $file->status->value,
          'description' => '',
          'upload' => '',
        ];
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function saveImage($type, $image) {

    // Prepare function name and throw an exception if it doesn't match for an
    // existing function.
    $image_dir = 'public://';
    switch ($type) {
      case self::IMAGE_TYPE_THUMBNAIL:
        $image_dir .= self::VIDEOS_IMAGES_THUMBNAILS_DIR;
        break;
      case self::IMAGE_TYPE_POSTER:
        $image_dir .= self::VIDEOS_IMAGES_POSTERS_DIR;
        break;
      default:
        throw new \Exception(t("Invalid type given: @type, the type argument must be either '@thumbnail' or '@poster'.", [
          '@type' => $type,
          '@thumbnail' => self::IMAGE_TYPE_THUMBNAIL,
          '@poster' => self::IMAGE_TYPE_POSTER,
        ]));
    }

    // Make type's first character uppercase for correct function name.
    $function = ucfirst($type);
    $needs_save = TRUE;

    // Try to get the image's filename from Brightcove.
    // @TODO: Find a drupal friendly solution for file handling.
    preg_match('/\\/(?!.*\\/)([\\w\\.-]+)/i', $img_src = is_array($image) ? $image['src'] : $image
      ->getSrc(), $matches);
    if (isset($matches[1])) {

      // Get entity's image file.

      /** @var \Drupal\file\Entity\File $file */
      $entity_image = $this
        ->{"get{$function}"}();

      // If the entity already has an image then load and delete it.
      if (!empty($entity_image['target_id'])) {
        $file = File::load($entity_image['target_id']);
        if (!is_null($file) && $file
          ->getFileName() != $matches[1]) {
          $this
            ->{"set{$function}"}(NULL);
        }
        elseif (!is_null($file)) {
          $file_path = \Drupal::service('file_system')
            ->realpath($file
            ->getFileUri());
          $file_md5 = md5_file($file_path);
          $image_md5 = md5_file($image
            ->getSrc());
          if ($file_md5 !== FALSE && $file_md5 === $image_md5) {
            $needs_save = FALSE;
          }
        }
      }

      // Save the new image from Brightcove to the entity.
      if ($needs_save) {
        $image_content = file_get_contents($img_src);

        // Prepare directory and if it was a success try to save the image.
        if (file_prepare_directory($image_dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY)) {
          $image_name = $matches[1];
          $file = file_save_data($image_content, "{$image_dir}/{$image_name}");

          // Set image if there was no error.
          if ($file !== FALSE) {
            $this
              ->{"set{$function}"}($file
              ->id());
          }
        }
      }
    }
    return $this;
  }

  /**
   * Helper function to delete a file from the entity.
   *
   * @param int $target_id
   *   The target ID of the saved file.
   *
   * @return \Drupal\brightcove\BrightcoveVideoInterface
   *   The called Brightcove Video.
   *
   * @throws \Exception
   *   If the $target_id is not a positive number or zero.
   */
  private function deleteFile($target_id) {
    if (!is_numeric($target_id) || $target_id <= 0) {
      throw new \Exception(t('Target ID must be non-zero number.'));
    }

    /** @var \Drupal\file\Entity\File $file */
    $file = File::load($target_id);

    // Delete image.
    // @TODO: Check for multiple file references when it will be needed.
    // So far as I find it, it is not possible to create multiple file
    // references on the Drupal's UI, so it should be OK now.
    if (!is_null($file)) {
      $file
        ->delete();
    }
    return $this;
  }

  /**
   * Create an ingestion request for image.
   *
   * @param string $type
   *   The type of the image, possible values are:
   *     - IMAGE_TYPE_POSTER
   *     - IMAGE_TYPE_THUMBNAIL
   *   .
   *
   * @throws \Exception
   *   If the $type is not matched with the possible types.
   */
  protected function createIngestImage($type) {
    if (!in_array($type, [
      self::IMAGE_TYPE_POSTER,
      self::IMAGE_TYPE_THUMBNAIL,
    ])) {
      throw new \Exception(t("Invalid type given: @type, the type argument must be either '@thumbnail' or '@poster'.", [
        '@type' => $type,
        '@thumbnail' => self::IMAGE_TYPE_THUMBNAIL,
        '@poster' => self::IMAGE_TYPE_POSTER,
      ]));
    }
    $function = ucfirst($type);

    // Set up image ingestion.
    if (!empty($this
      ->{"get{$function}"}()['target_id'])) {
      $ingest_request = $this
        ->getIngestRequest();

      /** @var \Drupal\file\Entity\File $file */
      $file = File::load($this
        ->{"get{$function}"}()['target_id']);

      // Load the image object factory so we can access height and width.
      $image_factory = \Drupal::service('image.factory');
      $image = $image_factory
        ->get($file
        ->getFileUri());
      if (!is_null($image)) {
        $ingest_image = new IngestImage();
        $ingest_image
          ->setUrl(file_create_url($file
          ->getFileUri()));
        $ingest_image
          ->setWidth($image
          ->getWidth());
        $ingest_image
          ->setHeight($image
          ->getHeight());
        $ingest_request
          ->{"set{$function}"}($ingest_image);
      }
    }
  }

  /**
   * Get a random hash token for ingestion request callback.
   *
   * @return string|null
   *   The generated random token or NULL if an error happened.
   */
  protected function getIngestionToken() {
    $token = NULL;
    try {

      // Generate unique token.
      do {
        $token = Crypt::hmacBase64($this
          ->getBrightcoveId(), Crypt::randomBytesBase64() . Settings::getHashSalt());
      } while (\Drupal::keyValueExpirable('brightcove_callback')
        ->has($token));

      // Insert unique token into database.
      \Drupal::keyValueExpirable('brightcove_callback')
        ->setWithExpire($token, $this
        ->id(), \Drupal::config('brightcove.settings')
        ->get('notification.callbackExpirationTime'));
    } catch (\Exception $e) {
      watchdog_exception('brightcove', $e);

      // Reset token to NULL.
      $token = NULL;
    }
    return $token;
  }

  /**
   * {@inheritdoc}
   */
  public function getBrightcoveId() {
    return $this
      ->get('video_id')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setBrightcoveId($id) {
    $this
      ->set('video_id', $id);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getDuration() {
    return $this
      ->get('duration')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setDuration($duration) {
    $this
      ->set('duration', $duration);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getRelatedLink() {
    $value = $this
      ->get('related_link')
      ->getValue();
    if (empty($value[0])) {
      return [];
    }

    // Original entity missing this array value, so to be consistent when
    // comparing the original entity with new entity values add this array
    // value if missing.
    if (!isset($value[0]['attributes'])) {
      $value[0]['attributes'] = [];
    }
    return $value[0];
  }

  /**
   * {@inheritdoc}
   */
  public function setRelatedLink($related_link) {

    // If the protocol is missing from the link add default http protocol to
    // the link.
    if (!empty($related_link['uri']) && !preg_match('/[\\w-]+:\\/\\//i', $related_link['uri'])) {
      $related_link['uri'] = "http://{$related_link['uri']}";
    }
    $this
      ->set('related_link', $related_link);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getLongDescription() {
    return $this
      ->get('long_description')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setLongDescription($long_description) {
    $this
      ->set('long_description', $long_description);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getEconomics() {
    return $this
      ->get('economics')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setEconomics($economics) {
    $this
      ->set('economics', $economics);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getVideoFile() {
    $value = $this
      ->get('video_file')
      ->getValue();
    if (empty($value[0]['target_id'])) {
      return [];
    }
    if (!isset($value[0]['upload'])) {
      $value[0]['upload'] = '';
    }
    return $value[0];
  }

  /**
   * {@inheritdoc}
   */
  public function setVideoFile($video_file) {
    $video_to_delete = $this
      ->getVideoFile();
    if ($video_file == NULL && !empty($video_to_delete['target_id'])) {
      $this
        ->deleteFile($video_to_delete['target_id']);
    }
    $this
      ->set('video_file', $video_file);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getVideoUrl() {
    return $this
      ->get('video_url')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setVideoUrl($video_url) {
    $this
      ->set('video_url', $video_url);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getProfile() {
    return $this
      ->get('profile')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setProfile($profile) {
    $this
      ->set('profile', $profile);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getPoster() {
    $values = $this
      ->get('poster')
      ->getValue();
    if (empty($values[0]['target_id'])) {
      return NULL;
    }
    $this
      ->provideDefaultValuesForImageField($values);
    return $values[0];
  }

  /**
   * {@inheritdoc}
   */
  public function setPoster($poster) {

    // Handle image deletion here as well.
    $poster_to_delete = $this
      ->getPoster();
    if (is_null($poster) && !empty($poster_to_delete['target_id'])) {
      $this
        ->deleteFile($poster_to_delete['target_id']);
    }
    $this
      ->set('poster', $poster);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getThumbnail() {
    $values = $this
      ->get('thumbnail')
      ->getValue();
    if (empty($values[0]['target_id'])) {
      return NULL;
    }
    $this
      ->provideDefaultValuesForImageField($values);
    return $values[0];
  }

  /**
   * {@inheritdoc}
   */
  public function setThumbnail($thumbnail) {

    // Handle image deletion here as well.
    $thumbnail_to_delete = $this
      ->getThumbnail();
    if (is_null($thumbnail) && !empty($thumbnail_to_delete['target_id'])) {
      $this
        ->deleteFile($thumbnail_to_delete['target_id']);
    }
    $this
      ->set('thumbnail', $thumbnail);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getCustomFieldValues() {
    $value = $this
      ->get('custom_field_values')
      ->getValue();
    if (!empty($value)) {
      return $value[0];
    }
    return $value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCustomFieldValues(array $values) {
    return $this
      ->set('custom_field_values', $values);
  }

  /**
   * {@inheritdoc}
   */
  public function getScheduleStartsAt() {
    $value = $this
      ->get('schedule_starts_at')
      ->getValue();
    if (empty($value)) {
      return NULL;
    }
    return $value[0]['value'];
  }

  /**
   * {@inheritdoc}
   */
  public function setScheduleStartsAt($schedule_starts_at) {
    $this
      ->set('schedule_starts_at', $schedule_starts_at);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getScheduleEndsAt() {
    $value = $this
      ->get('schedule_ends_at')
      ->getValue();
    if (empty($value)) {
      return NULL;
    }
    return $value[0]['value'];
  }

  /**
   * {@inheritdoc}
   */
  public function setScheduleEndsAt($schedule_ends_at) {
    $this
      ->set('schedule_ends_at', $schedule_ends_at);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getTextTracks() {
    return $this
      ->get('text_tracks')
      ->getValue();
  }

  /**
   * {@inheritdoc}
   */
  public function setTextTracks($text_tracks) {
    return $this
      ->set('text_tracks', $text_tracks);
  }

  /**
   * Loads a Video based on the Brightcove Video ID and Account ID.
   *
   * @param string $account_id
   *   The ID of the account.
   * @param string $brightcove_video_id
   *   The External ID of the Video.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The matching Brightcove Video or NULL if the video cannot be found.
   */
  public static function loadByBrightcoveVideoId($account_id, $brightcove_video_id) {

    // Get API Client by Account ID.
    $api_client_ids = \Drupal::entityQuery('brightcove_api_client')
      ->condition('account_id', $account_id)
      ->execute();
    $entity_ids = \Drupal::entityQuery('brightcove_video')
      ->condition('api_client', reset($api_client_ids))
      ->condition('video_id', $brightcove_video_id)
      ->condition('status', self::PUBLISHED)
      ->execute();
    if (!empty($entity_ids)) {
      return self::load(reset($entity_ids));
    }
    return NULL;
  }

  /**
   * {@inheritdoc}
   *
   * @param bool $upload
   *   Whether to upload the video to Brightcove or not.
   */
  public function save($upload = FALSE) {

    // Check if it will be a new entity or an existing one being updated.
    $status = $this
      ->id() ? SAVED_UPDATED : SAVED_NEW;

    // Make sure that preSave runs before any modification is made for the
    // entity.
    $saved = parent::save();

    // Upload data for Brightcove only if we saved the video from form.
    if ($upload) {
      $cms = BrightcoveUtil::getCmsApi($this
        ->getApiClient());

      // Setup video object and set minimum required values.
      $video = new Video();
      $video
        ->setName($this
        ->getName());

      // Save or update description if needed.
      if ($this
        ->isFieldChanged('description')) {
        $video
          ->setDescription($this
          ->getDescription());
      }

      // Save or update duration if needed.
      if ($this
        ->isFieldChanged('duration')) {
        $video
          ->setDuration($this
          ->getDuration());
      }

      // Save or update economics if needed.
      if ($this
        ->isFieldChanged('economics')) {
        $video
          ->setEconomics($this
          ->getEconomics());
      }

      // Save or update tags if needed.
      if ($this
        ->isFieldChanged('tags')) {

        // Get term IDs.
        $term_ids = [];
        foreach ($this
          ->getTags() as $tag) {
          $term_ids[] = $tag['target_id'];
        }

        // Load terms.

        /** @var \Drupal\taxonomy\Entity\Term[] $terms */
        $terms = Term::loadMultiple($term_ids);
        $tags = [];
        foreach ($terms as $term) {
          $tags[] = $term
            ->getName();
        }
        $video
          ->setTags($tags);
      }

      // Save or update link if needed.
      if ($this
        ->isFieldChanged('related_link')) {
        $link = new Link();
        $related_link = $this
          ->getRelatedLink();
        $is_link_set = FALSE;
        if (!empty($related_link['uri'])) {
          $link
            ->setUrl(Url::fromUri($related_link['uri'], [
            'absolute' => TRUE,
          ])
            ->toString());
          $is_link_set = TRUE;
        }
        if (!empty($related_link['title'])) {
          $link
            ->setText($related_link['title']);
          $is_link_set = TRUE;
        }
        if ($is_link_set) {
          $video
            ->setLink($link);
        }
        else {
          $video
            ->setLink();
        }
      }

      // Save or update long description if needed.
      if ($this
        ->isFieldChanged('long_description')) {
        $video
          ->setLongDescription($this
          ->getLongDescription());
      }

      // Save or update reference ID if needed.
      if ($this
        ->isFieldChanged('reference_id')) {
        $video
          ->setReferenceId($this
          ->getReferenceId());
      }

      // Save or update custom field values.
      $custom_field_num = \Drupal::entityQuery('brightcove_custom_field')
        ->condition('api_client', $this
        ->getApiClient())
        ->count()
        ->execute();
      if ($this
        ->isFieldChanged('custom_field_values') && $custom_field_num) {
        $video
          ->setCustomFields($this
          ->getCustomFieldValues());
      }

      // Save or update schedule start at date if needed.
      if ($this
        ->isFieldChanged('schedule_starts_at') || $this
        ->isFieldChanged('schedule_ends_at')) {
        $starts_at = $this
          ->getScheduleStartsAt();
        $ends_at = $this
          ->getScheduleEndsAt();
        $schedule = new Schedule();
        $is_schedule_set = FALSE;
        if (!is_null($starts_at)) {
          $schedule
            ->setStartsAt($starts_at . '.000Z');
          $is_schedule_set = TRUE;
        }
        if (!is_null($ends_at)) {
          $schedule
            ->setEndsAt($ends_at . '.000Z');
          $is_schedule_set = TRUE;
        }
        if ($is_schedule_set) {
          $video
            ->setSchedule($schedule);
        }
        else {
          $video
            ->setSchedule();
        }
      }

      // Upload text tracks.
      if ($this
        ->isFieldChanged('text_tracks')) {
        $video_text_tracks = [];
        $ingest_text_tracks = [];
        foreach ($this
          ->getTextTracks() as $text_track) {
          if (!empty($text_track['target_id'])) {

            /** @var \Drupal\brightcove\Entity\BrightcoveTextTrack $text_track_entity */
            $text_track_entity = BrightcoveTextTrack::load($text_track['target_id']);
            if (!is_null($text_track_entity)) {

              // Setup ingestion request if there was a text track uploaded.
              $webvtt_file = $text_track_entity
                ->getWebVttFile();
              if (!empty($webvtt_file[0]['target_id'])) {

                /** @var \Drupal\file\Entity\File $file */
                $file = File::load($webvtt_file[0]['target_id']);
                if (!is_null($file)) {
                  $ingest_text_tracks[] = (new IngestTextTrack())
                    ->setSrclang($text_track_entity
                    ->getSourceLanguage())
                    ->setUrl(file_create_url($file
                    ->getFileUri()))
                    ->setKind($text_track_entity
                    ->getKind())
                    ->setLabel($text_track_entity
                    ->getLabel())
                    ->setDefault($text_track_entity
                    ->isDefault());
                }
              }
              else {
                $video_text_track = (new TextTrack())
                  ->setId($text_track_entity
                  ->getTextTrackId())
                  ->setSrclang($text_track_entity
                  ->getSourceLanguage())
                  ->setLabel($text_track_entity
                  ->getLabel())
                  ->setKind($text_track_entity
                  ->getKind())
                  ->setMimeType($text_track_entity
                  ->getMimeType())
                  ->setAssetId($text_track_entity
                  ->getAssetId());

                // If asset ID is set the src will be ignored, so in this case
                // we don't set the src.
                if (!empty($text_track_entity
                  ->getAssetId())) {
                  $video_text_track
                    ->setAssetId($text_track_entity
                    ->getAssetId());
                }
                else {
                  $video_text_track
                    ->setSrc($text_track_entity
                    ->getSource());
                }

                // Get text track sources.
                $video_text_track_sources = [];
                foreach ($text_track_entity
                  ->getSources() as $source) {
                  $text_track_source = new TextTrackSource();
                  $text_track_source
                    ->setSrc($source['uri']);
                  $video_text_track_sources[] = $text_track_source;
                }
                $video_text_track
                  ->setSources($video_text_track_sources);
                $video_text_tracks[] = $video_text_track;
              }
            }
          }
        }

        // Set existing text tracks.
        $video
          ->setTextTracks($video_text_tracks);
      }

      // Update status field based on Brightcove's Video state.
      if ($this
        ->isFieldChanged('status')) {
        $video
          ->setState($this
          ->isPublished() ? self::STATE_ACTIVE : self::STATE_INACTIVE);
      }

      // Create or update a video.
      switch ($status) {
        case SAVED_NEW:

          // Create new video on Brightcove.
          $saved_video = $cms
            ->createVideo($video);

          // Set the rest of the fields on BrightcoveVideo entity.
          $this
            ->setBrightcoveId($saved_video
            ->getId());
          $this
            ->setCreatedTime(strtotime($saved_video
            ->getCreatedAt()));
          break;
        case SAVED_UPDATED:

          // Set Video ID.
          $video
            ->setId($this
            ->getBrightcoveId());

          // Update video.
          $saved_video = $cms
            ->updateVideo($video);
          break;
      }

      // Set ingestion for thumbnail.
      if ($this
        ->isFieldChanged(self::IMAGE_TYPE_THUMBNAIL)) {
        $this
          ->createIngestImage(self::IMAGE_TYPE_THUMBNAIL);
      }

      // Set ingestion for poster.
      if ($this
        ->isFieldChanged(self::IMAGE_TYPE_POSTER)) {
        $this
          ->createIngestImage(self::IMAGE_TYPE_POSTER);
      }

      // Set ingestion for video.
      if ($this
        ->isFieldChanged('video_file') && !empty($this
        ->getVideoFile())) {

        /** @var \Drupal\file\Entity\File $file */
        $file = File::load($this
          ->getVideoFile()['target_id']);
        $ingest_request = $this
          ->getIngestRequest();
        $ingest_master = new IngestRequestMaster();
        $ingest_master
          ->setUrl(file_create_url($file
          ->getFileUri()));
        $ingest_request
          ->setMaster($ingest_master);
        $profiles = self::getProfileAllowedValues($this
          ->getApiClient());
        $ingest_request
          ->setProfile($profiles[$this
          ->getProfile()]);
      }

      // Set ingestion for video url.
      if ($this
        ->isFieldChanged('video_url') && !empty($this
        ->getVideoUrl())) {
        $ingest_request = $this
          ->getIngestRequest();
        $ingest_master = new IngestRequestMaster();
        $ingest_master
          ->setUrl($this
          ->getVideoUrl());
        $ingest_request
          ->setMaster($ingest_master);
        $profiles = self::getProfileAllowedValues($this
          ->getApiClient());
        $ingest_request
          ->setProfile($profiles[$this
          ->getProfile()]);
      }

      // Set ingestion for text tracks.
      if (!empty($ingest_text_tracks)) {
        $ingest_request = $this
          ->getIngestRequest();
        $ingest_request
          ->setTextTracks($ingest_text_tracks);
      }

      // Update changed time and video entity with the video ID.
      if (isset($saved_video)) {
        $this
          ->setChangedTime(strtotime($saved_video
          ->getUpdatedAt()));

        // Save the entity again to save some new values which are only
        // available after creating/updating the video on Brightcove.
        // Also don't change the save state to show the correct message when if
        // the entity is created or updated.
        parent::save();
      }

      // Send the ingest request if there was an ingestible asset.
      if (!is_null($this->ingestRequest)) {

        // Get token.
        $token = $this
          ->getIngestionToken();

        // Make sure that the token is generated successfully. If there was an
        // error generating the token then be nice to Brightcove and don't set
        // the callback url, so it won't hit a wall by trying to notify us on a
        // non-valid URL.
        if (!is_null($token)) {
          $callback_url = Url::fromRoute('brightcove_ingestion_callback', [
            'token' => $token,
          ], [
            'absolute' => TRUE,
          ])
            ->toString();
          $this->ingestRequest
            ->setCallbacks([
            $callback_url,
          ]);
        }

        // Send request.
        $di = BrightcoveUtil::getDiApi($this
          ->getApiClient());
        $di
          ->createIngest($this
          ->getBrightcoveId(), $this->ingestRequest);
      }
    }

    // Reset changed fields.
    $this->changedFields = [];
    return $saved;
  }

  /**
   * {@inheritdoc}
   *
   * @param bool $local_only
   *   Whether to delete the local version only or both local and Brightcove
   *   versions.
   */
  public function delete($local_only = FALSE) {

    // Delete video from Brightcove.
    if (!$this
      ->isNew() && !$local_only) {
      $api_client = BrightcoveUtil::getApiClient($this
        ->getApiClient());
      $client = $api_client
        ->getClient();

      // Delete video references.
      try {
        $client
          ->request('DELETE', 1, 'cms', $api_client
          ->getAccountId(), "/videos/{$this->getBrightcoveId()}/references", NULL);

        // Delete video.
        $cms = BrightcoveUtil::getCmsApi($this
          ->getApiClient());
        $cms
          ->deleteVideo($this
          ->getBrightcoveId());
        parent::delete();
      } catch (APIException $e) {
        if ($e
          ->getCode() == 404) {
          drupal_set_message(t('The video was not found on Brightcove, only the local version was deleted.'), 'warning');
          parent::delete();
        }
        else {
          drupal_set_message(t('There was an error while trying to delete the Video from Brightcove: @error', [
            '@error' => $e
              ->getMessage(),
          ]), 'error');
        }
      }
    }
    else {
      parent::delete();
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {

    // Set weights based on the real order of the fields.
    $weight = -30;

    /*
     * Drupal-specific fields first.
     *
     * bcvid - Brightcove Video ID (Drupal-internal).
     * uuid - UUID.
     * - Title comes here, but that's the "Name" field from Brightcove.
     * langcode - Language.
     * api_client - Entityreference to BrightcoveAPIClient.
     * - Brightcove fields come here.
     * uid - Author.
     * created - Posted.
     * changed - Last modified.
     */
    $fields['bcvid'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('ID'))
      ->setDescription(t('The Drupal entity ID of the Brightcove Video.'))
      ->setReadOnly(TRUE);
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The Brightcove Video UUID.'))
      ->setReadOnly(TRUE);
    $fields['api_client'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('API Client'))
      ->setDescription(t('Brightcove API credentials (account) to use.'))
      ->setRequired(TRUE)
      ->setSetting('target_type', 'brightcove_api_client')
      ->setDisplayOptions('form', [
      'type' => 'options_select',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['player'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Player'))
      ->setDescription(t('Brightcove Player to be used for playback.'))
      ->setSetting('target_type', 'brightcove_player')
      ->setDisplayOptions('form', [
      'type' => 'options_select',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // Status field, tied together with the status of the entity.
    $fields['status'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Enabled'))
      ->setDescription(t('Determines whether the video is playable.'))
      ->setDefaultValue(TRUE)
      ->setSettings([
      'on_label' => t('Active'),
      'off_label' => t('Inactive'),
    ])
      ->setDisplayOptions('form', [
      'type' => 'boolean_checkbox',
      'label' => 'above',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'boolean',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['name'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Name'))
      ->setDescription(t('Title of the video.'))
      ->setRequired(TRUE)
      ->setSettings([
      // Not applying the max_length setting any longer. Without an explicit
      // max_length setting Drupal will use a varchar(255) field, at least on
      // my MySQL backend. BC docs currently say the length of the 'name'
      // field is 1..255, but let's just not apply any explicit limit any
      // longer on the Drupal end.
      'text_processing' => 0,
    ])
      ->setDisplayOptions('form', [
      'type' => 'string_textfield',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'string',
      'label' => 'hidden',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE);
    $fields['langcode'] = BaseFieldDefinition::create('language')
      ->setLabel(t('Language code'))
      ->setDescription(t('The language code for the Brightcove Video.'))
      ->setDisplayOptions('form', [
      'type' => 'language_select',
      'weight' => ++$weight,
    ])
      ->setDisplayConfigurable('form', TRUE);

    /*
     * Additional Brightcove fields, based on
     * @see https://videocloud.brightcove.com/admin/fields
     * superseded by
     * @see http://docs.brightcove.com/en/video-cloud/cms-api/references/cms-api/versions/v1/index.html#api-videoGroup-Get_Videos
     * superseded by
     * @see http://docs.brightcove.com/en/video-cloud/cms-api/references/cms-api/versions/v1/index.html#api-videoGroup-Create_Video
     *
     * Brightcove ID - string (Not editable. Unique Video ID assigned by
     *   Brightcove)
     * Economics - list (ECONOMICS_TYPE_FREE, ECONOMICS_TYPE_AD_SUPPORTED)
     * Force Ads - boolean
     * Geo-filtering Country List - list (ISO-3166 country code list)
     * Geo-filtering On - boolean
     * Geo-filtering Options - list (Include countries, Exclude Countries)
     * Logo Overlay Alignment - list (Top Left, Top Right, Bottom Right,
     *   Bottom Left)
     * Logo Overlay Image - image file (Transparent PNG or GIF)
     * Logo Overlay Tooltip - text(128)
     * Logo Overlay URL - URL(128)
     * Long Description - string(0..5000)
     * Bumper Video - video file (FLV or H264 video file to playback before the
     *   Video content)
     * Reference ID - string(..150) (Value specified must be unique)
     * Related Link Text - text(40)
     * Scheduling End Date - date (Day/Time for the video to be hidden in the
     *   player)
     * Scheduling Start Date - date (Day/Time for the video be displayed in the
     *   player)
     * Short Description - string(0..250)
     * Tags - text (Separate tags with a comma; no tag > 128 characters. Max
     *   1200 tags per video)
     * Thumbnail - image file (Suggested size: 120 x 90 pixels, JPG)
     * Video Duration - number (Not editable. Stores the length of the video
     *   file.)
     * Video Files - video file (One or more FLV or H264 video files)
     * Video Name - string(1..255)
     * Video Still - image file (Suggested size: 480 x 360 pixels, JPG)
     * Viral Distribution - boolean (Enables the get code and blogging menu
     *   options for the video)
     */
    $fields['video_id'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Video ID'))
      ->setDescription(t('Unique Video ID assigned by Brightcove.'))
      ->setReadOnly(TRUE)
      ->setDisplayOptions('view', [
      'type' => 'string',
      'label' => 'inline',
      'weight' => ++$weight,
    ])
      ->setDisplayConfigurable('view', TRUE);
    $fields['duration'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Video Duration'))
      ->setReadOnly(TRUE)
      ->setDisplayOptions('view', [
      'type' => 'number_time',
      'label' => 'inline',
      'weight' => ++$weight,
      'settings' => [
        'storage' => TimeFieldFormatter::STORAGE_MILLISECONDS,
        'display' => TimeFieldFormatter::DISPLAY_NUMBERSMS,
      ],
    ])
      ->setDisplayConfigurable('view', TRUE);
    $fields['description'] = BaseFieldDefinition::create('string_long')
      ->setLabel(t('Short description'))
      ->setDescription(t('Max 250 characters.'))
      ->setDisplayOptions('form', [
      'type' => 'string_textarea',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'basic_string',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
      ->addPropertyConstraints('value', [
      'Length' => [
        'max' => 250,
      ],
    ]);
    $fields['tags'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Tags'))
      ->setDescription(t('Max 1200 tags per video'))
      ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
      ->setSettings([
      'target_type' => 'taxonomy_term',
      'handler_settings' => [
        'target_bundles' => [
          self::TAGS_VID => self::TAGS_VID,
        ],
        'auto_create' => TRUE,
      ],
    ])
      ->setDisplayOptions('form', [
      'type' => 'entity_reference_autocomplete',
      'weight' => ++$weight,
      'settings' => [
        'autocomplete_type' => 'tags',
      ],
    ])
      ->setDisplayOptions('view', [
      'type' => 'entity_reference_label',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['related_link'] = BaseFieldDefinition::create('link')
      ->setLabel(t('Related Link'))
      ->setSettings([
      'max_length' => 150,
      'link_type' => LinkItemInterface::LINK_GENERIC,
      'title' => DRUPAL_OPTIONAL,
    ])
      ->setDisplayOptions('form', [
      'type' => 'link_default',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'link',
      'label' => 'inline',
      'weight' => $weight,
      'settings' => [
        'trim_length' => 150,
        'target' => '_blank',
      ],
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['reference_id'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Reference ID'))
      ->addConstraint('UniqueField')
      ->setDescription(t('Value specified must be unique'))
      ->setSettings([
      'max_length' => 150,
      'text_processing' => 0,
    ])
      ->setDisplayOptions('form', [
      'type' => 'string_textfield',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'string',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDefaultValueCallback(static::class . '::getDefaultReferenceId')
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['long_description'] = BaseFieldDefinition::create('string_long')
      ->setLabel(t('Long description'))
      ->setDescription(t('Max 5000 characters'))
      ->setDisplayOptions('form', [
      'type' => 'string_textarea',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'basic_string',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
      ->addPropertyConstraints('value', [
      'Length' => [
        'max' => 5000,
      ],
    ]);

    // Advertising field, but Brightcove calls it 'economics' in the API.
    $fields['economics'] = BaseFieldDefinition::create('list_string')
      ->setLabel(t('Advertising'))
      ->setRequired(TRUE)
      ->setDefaultValue(self::ECONOMICS_TYPE_FREE)
      ->setSetting('allowed_values', [
      self::ECONOMICS_TYPE_FREE => 'Free',
      self::ECONOMICS_TYPE_AD_SUPPORTED => 'Ad Supported',
    ])
      ->setDisplayOptions('form', [
      'type' => 'options_buttons',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'string',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // @TODO: Folder
    $fields['video_file'] = BaseFieldDefinition::create('file')
      ->setLabel(t('Video source'))
      ->setSettings([
      'file_extensions' => '3gp 3g2 aac ac3 asf avchd avi avs bdav dv dxa ea eac3 f4v flac flv h261 h263 h264 m2p m2ts m4a m4v mjpeg mka mks mkv mov mp3 mp4 mpeg mpegts mpg mt2s mts ogg ps qt rtsp thd ts vc1 wav webm wma wmv',
      'file_directory' => '[random:hash:md5]',
    ])
      ->setDisplayOptions('form', [
      'type' => 'file_generic',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'file_url_plain',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // Provide an external URL.
    $fields['video_url'] = BaseFieldDefinition::create('uri')
      ->setLabel(t('Video source URL'))
      ->setDisplayOptions('form', [
      'type' => 'uri',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'uri_link',
      'label' => 'inline',
      'weight' => $weight,
      'settings' => [
        'trim_length' => 150,
        'target' => '_blank',
      ],
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['profile'] = BaseFieldDefinition::create('list_string')
      ->setLabel(t('Encoding profile'))
      ->setRequired(TRUE)
      ->setSetting('allowed_values_function', [
      self::class,
      'profileAllowedValues',
    ])
      ->setDisplayOptions('form', [
      'type' => 'options_select',
      'weight' => ++$weight,
    ])
      ->setDisplayConfigurable('form', TRUE);
    $fields['poster'] = BaseFieldDefinition::create('image')
      ->setLabel(t('Video Still'))
      ->setSettings([
      'file_extensions' => 'jpg jpeg png',
      'file_directory' => self::VIDEOS_IMAGES_POSTERS_DIR,
      'alt_field' => FALSE,
      'alt_field_required' => FALSE,
    ])
      ->setDisplayOptions('form', [
      'type' => 'image_image',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'image',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['thumbnail'] = BaseFieldDefinition::create('image')
      ->setLabel(t('Thumbnail'))
      ->setSettings([
      'file_extensions' => 'jpg jpeg png',
      'file_directory' => self::VIDEOS_IMAGES_THUMBNAILS_DIR,
      'alt_field' => FALSE,
      'alt_field_required' => FALSE,
    ])
      ->setDisplayOptions('form', [
      'type' => 'image_image',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'image',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['custom_field_values'] = BaseFieldDefinition::create('map');
    $fields['schedule_starts_at'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('Scheduled Start Date'))
      ->setDescription(t('If not specified, the video will be Available Immediately.'))
      ->setDisplayOptions('form', [
      'type' => 'datetime_default',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'datetime_default',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['schedule_ends_at'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('Scheduled End Date'))
      ->setDescription(t('If not specified, the video will have No End Date.'))
      ->setDisplayOptions('form', [
      'type' => 'datetime_default',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'datetime_default',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['text_tracks'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Text Tracks'))
      ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
      ->setDescription(t('Referenced text tracks which belong to the video.'))
      ->setSetting('target_type', 'brightcove_text_track')
      ->setDisplayOptions('form', [
      'type' => 'brightcove_inline_entity_form_complex',
      'settings' => [
        'allow_new' => TRUE,
        'allow_existing' => FALSE,
      ],
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      'type' => 'entity_reference_label',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['uid'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Authored by'))
      ->setDescription(t('The username of the Brightcove Video author.'))
      ->setTranslatable(TRUE)
      ->setDefaultValueCallback('Drupal\\brightcove\\Entity\\BrightcoveVideo::getCurrentUserId')
      ->setSetting('target_type', 'user')
      ->setDisplayOptions('form', [
      'type' => 'entity_reference_autocomplete',
      'weight' => ++$weight,
      'settings' => [
        'match_operator' => 'CONTAINS',
        'size' => '60',
        'autocomplete_type' => 'tags',
        'placeholder' => '',
      ],
    ])
      ->setDisplayOptions('view', [
      'type' => 'author',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['created'] = BaseFieldDefinition::create('created')
      ->setLabel(t('Created'))
      ->setDescription(t('The time that the Brightcove Video was created.'))
      ->setTranslatable(TRUE)
      ->setDisplayOptions('view', [
      'label' => 'inline',
      'type' => 'timestamp',
      'weight' => ++$weight,
    ])
      ->setDisplayConfigurable('view', TRUE);
    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time that the Brightcove Video was last edited.'))
      ->setTranslatable(TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['force_ads'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Force Ads'))
      ->setDefaultValue(FALSE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['geo_countries'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Geo-filtering Country List'))
      ->setDescription(t('ISO-3166 country code list.'))
      ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
      ->setSettings([
      'max_length' => 5,
      'text_processing' => 0,
    ])
      ->setDisplayOptions('form', [
      // Usable default type: string_textfield.
      'type' => 'hidden',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      // Usable default type: string.
      'type' => 'hidden',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['geo_restricted'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Geo-filtering On'))
      ->setDefaultValue(FALSE)
      ->setDisplayOptions('form', [
      // Usable default type: boolean_checkbox.
      'type' => 'hidden',
      'weight' => ++$weight,
      'settings' => [
        'display_label' => TRUE,
      ],
    ])
      ->setDisplayOptions('view', [
      // Usable default type: string.
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['geo_exclude_countries'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Geo-filtering Options: Exclude countries'))
      ->setDescription(t('If enabled, country list is treated as a list of countries excluded from viewing.'))
      ->setDisplayOptions('form', [
      // Usable default type: boolean_checkbox.
      'type' => 'hidden',
      'weight' => ++$weight,
      'settings' => [
        'display_label' => TRUE,
      ],
    ])
      ->setDisplayOptions('view', [
      // Usable default type: string.
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['logo_alignment'] = BaseFieldDefinition::create('list_string')
      ->setLabel(t('Logo Overlay Alignment'))
      ->setCardinality(4)
      ->setSetting('allowed_values', [
      'top_left' => 'Top Left',
      'top_right' => 'Top Right',
      'bottom_left' => 'Bottom Left',
      'bottom_right' => 'Bottom Right',
    ])
      ->setDisplayOptions('form', [
      // Usable default type: options_select.
      'type' => 'hidden',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      // Usable default type: string.
      'type' => 'hidden',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['logo_image'] = BaseFieldDefinition::create('image')
      ->setLabel(t('Logo Overlay Image'))
      ->setSettings([
      'file_extensions' => 'png gif',
      'file_directory' => '[random:hash:md5]',
      'alt_field' => FALSE,
      'alt_field_required' => FALSE,
    ])
      ->setDisplayOptions('form', [
      // Usable default type: image_image.
      'type' => 'hidden',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      // Usable default type: image.
      'type' => 'hidden',
      'label' => 'above',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['logo_tooltip'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Logo Overlay Tooltip'))
      ->setSettings([
      'max_length' => 128,
      'text_processing' => 0,
    ])
      ->setDisplayOptions('form', [
      // Usable default type: string_textfield.
      'type' => 'hidden',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      // Usable default type: string.
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['logo_url'] = BaseFieldDefinition::create('link')
      ->setLabel(t('Logo Overlay URL'))
      ->setSettings([
      'max_length' => 128,
      'link_type' => LinkItemInterface::LINK_GENERIC,
      'title' => DRUPAL_DISABLED,
    ])
      ->setDisplayOptions('form', [
      // Usable default type: link_default.
      'type' => 'hidden',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      // Usable default type: link.
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
      'settings' => [
        'trim_length' => 128,
        'target' => '_blank',
      ],
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['bumper_video'] = BaseFieldDefinition::create('file')
      ->setLabel(t('Bumper Video'))
      ->setDescription(t('FLV or H264 video file to playback before the Video content'))
      ->setSettings([
      'file_extensions' => 'flv',
      'file_directory' => '[random:hash:md5]',
    ])
      ->setDisplayOptions('form', [
      // Usable default type: file_generic.
      'type' => 'hidden',
      'weight' => ++$weight,
    ])
      ->setDisplayOptions('view', [
      // Usable default type: file_url_plain.
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Couldn't find this on the Brightcove UI: https://studio.brightcove.com/products/videocloud/media/videos/4585854207001
    $fields['viral'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Viral Distribution'))
      ->setDescription(t('Enables the get code and blogging menu options for the video'))
      ->setDefaultValue(FALSE)
      ->setDisplayOptions('form', [
      // Usable default type: boolean_checkbox.
      'type' => 'hidden',
      'weight' => ++$weight,
      'settings' => [
        'display_label' => TRUE,
      ],
    ])
      ->setDisplayOptions('view', [
      // Usable default type: string.
      'type' => 'hidden',
      'label' => 'inline',
      'weight' => $weight,
    ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    // FIXME: Cue points?
    return $fields;
  }

  /**
   * Gets the allowed values for video profile.
   *
   * @param string $api_client
   *   The API Client ID.
   *
   * @return array
   *   The list of profiles.
   */
  public static function getProfileAllowedValues($api_client) {
    $profiles = [];
    if (!empty($api_client)) {
      $cid = 'brightcove:video:profiles:' . $api_client;

      // If we have a hit in the cache, return the results.
      if ($cache = \Drupal::cache()
        ->get($cid)) {
        $profiles = $cache->data;
      }
      else {

        /** @var \Drupal\brightcove\Entity\BrightcoveAPIClient $api_client_entity */
        $api_client_entity = BrightcoveAPIClient::load($api_client);
        try {
          if (!is_null($api_client_entity)) {
            $client = $api_client_entity
              ->getClient();
            $json = $client
              ->request('GET', 1, 'ingestion', $api_client_entity
              ->getAccountId(), '/profiles', NULL);
            foreach ($json as $profile) {
              $profiles[$profile['id']] = $profile['name'];
            }

            // Order profiles by value.
            asort($profiles);

            // Save the results to cache.
            \Drupal::cache()
              ->set($cid, $profiles);
          }
          else {
            $profiles[] = t('Error: unable to fetch the list');
          }
        } catch (APIException $exception) {
          $profiles[] = t('Error: unable to fetch the list');
          watchdog_exception('brightcove', $exception);
        }
      }
    }
    return $profiles;
  }

  /**
   * Implements callback_allowed_values_function().
   *
   * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
   *   The field storage definition.
   * @param \Drupal\Core\Entity\FieldableEntityInterface|null $entity
   *   (optional) The entity context if known, or NULL if the allowed values
   *   are being collected without the context of a specific entity.
   * @param bool &$cacheable
   *   (optional) If an $entity is provided, the $cacheable parameter should be
   *   modified by reference and set to FALSE if the set of allowed values
   *   returned was specifically adjusted for that entity and cannot not be
   *   reused for other entities. Defaults to TRUE.
   *
   * @return array
   *   The array of allowed values. Keys of the array are the raw stored values
   *   (number or text), values of the array are the display labels. If $entity
   *   is NULL, you should return the list of all the possible allowed values
   *   in any context so that other code (e.g. Views filters) can support the
   *   allowed values for all possible entities and bundles.
   */
  public static function profileAllowedValues(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL, &$cacheable = TRUE) {
    $profiles = [];
    if ($entity instanceof BrightcoveVideo) {

      // Collect profiles for all of the api clients if the ID is not set.
      if (empty($entity
        ->id())) {
        $api_clients = \Drupal::entityQuery('brightcove_api_client')
          ->execute();
        foreach ($api_clients as $api_client_id) {
          $profiles[$api_client_id] = self::getProfileAllowedValues($api_client_id);
        }
      }
      else {
        $profiles = self::getProfileAllowedValues($entity
          ->getApiClient());
      }
    }
    return $profiles;
  }

  /**
   * Create or update an existing video from a Brightcove Video object.
   *
   * @param \Brightcove\Item\Video\Video $video
   *   Brightcove Video object.
   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
   *   EntityStorage.
   * @param int|null $api_client_id
   *   The ID of the BrightcoveAPIClient entity.
   *
   * @return \Drupal\brightcove\Entity\BrightcoveVideo|null
   *   The saved BrightcoveVideo entity.
   *
   * @throws \Exception
   *   If BrightcoveAPIClient ID is missing when a new entity is being created.
   */
  public static function createOrUpdate(Video $video, EntityStorageInterface $storage, $api_client_id = NULL) {

    // Try to get an existing video.
    $existing_video = $storage
      ->getQuery()
      ->condition('video_id', $video
      ->getId())
      ->execute();
    $needs_save = FALSE;

    // Update existing video.
    if (!empty($existing_video)) {

      // Load Brightcove Video.

      /** @var BrightcoveVideo $video_entity */
      $video_entity = self::load(reset($existing_video));

      // Update video if it is changed on Brightcove.
      if ($video_entity
        ->getChangedTime() < strtotime($video
        ->getUpdatedAt())) {
        $needs_save = TRUE;
      }
    }
    else {

      // Make sure we got an api client id when a new video is being created.
      if (is_null($api_client_id)) {
        throw new \Exception(t('To create a new BrightcoveVideo entity, the api_client_id must be given.'));
      }

      // Create new Brightcove video entity.
      $values = [
        'video_id' => $video
          ->getId(),
        'api_client' => [
          'target_id' => $api_client_id,
        ],
        'created' => strtotime($video
          ->getCreatedAt()),
      ];
      $video_entity = self::create($values);
      $needs_save = TRUE;
    }

    // Save entity only if it is being created or updated.
    if ($needs_save) {

      // Save or update changed time.
      $video_entity
        ->setChangedTime(strtotime($video
        ->getUpdatedAt()));

      // Save or update Description field if needed.
      if ($video_entity
        ->getDescription() != ($description = $video
        ->getDescription())) {
        $video_entity
          ->setDescription($description);
      }

      // Save or update duration field if needed.
      if ($video_entity
        ->getDuration() != ($duration = $video
        ->getDuration())) {
        $video_entity
          ->setDuration($duration);
      }

      // Save or update economics field if needed.
      if ($video_entity
        ->getEconomics() != ($economics = $video
        ->getEconomics())) {
        $video_entity
          ->setEconomics($economics);
      }

      // Save or update tags field if needed.
      BrightcoveUtil::saveOrUpdateTags($video_entity, $api_client_id, $video
        ->getTags());

      // Get images.
      $images = $video
        ->getImages();

      // Save or update thumbnail image if needed.
      if (!empty($images[self::IMAGE_TYPE_THUMBNAIL]) && !empty($images[self::IMAGE_TYPE_THUMBNAIL]
        ->getSrc())) {
        $video_entity
          ->saveImage(self::IMAGE_TYPE_THUMBNAIL, $images[self::IMAGE_TYPE_THUMBNAIL]);
      }
      else {

        // Delete file.
        $video_entity
          ->setThumbnail(NULL);
      }

      // Save or update poster image if needed.
      if (!empty($images[self::IMAGE_TYPE_POSTER]) && !empty($images[self::IMAGE_TYPE_POSTER]
        ->getSrc())) {
        $video_entity
          ->saveImage(self::IMAGE_TYPE_POSTER, $images[self::IMAGE_TYPE_POSTER]);
      }
      else {

        // Delete file.
        $video_entity
          ->setPoster(NULL);
      }

      // Save or update link url field if needed.
      $link = $video
        ->getLink();
      $related_link_field = $video_entity
        ->getRelatedLink() ?: NULL;
      $related_link = [];
      if (empty($related_link_field) && !empty($link)) {
        $related_link['uri'] = $link
          ->getUrl();
        $related_link['title'] = $link
          ->getText();
      }
      elseif (!empty($related_link_field) && !empty($link)) {
        if ($related_link_field['uri'] != ($url = $link
          ->getUrl())) {
          $related_link['uri'] = $url;
        }
        if ($related_link_field['title'] != ($title = $link
          ->getText())) {
          $related_link['title'] = $title;
        }
      }
      else {
        $video_entity
          ->setRelatedLink(NULL);
      }
      if (!empty($related_link)) {
        $video_entity
          ->setRelatedLink($related_link);
      }

      // Save or update long description if needed.
      if ($video_entity
        ->getLongDescription() != ($long_description = $video
        ->getLongDescription())) {
        $video_entity
          ->setLongDescription($long_description);
      }

      // Save or update Name field if needed.
      if ($video_entity
        ->getName() != ($name = $video
        ->getName())) {
        $video_entity
          ->setName($name);
      }

      // Save or update reference ID field if needed.
      if ($video_entity
        ->getReferenceId() != ($reference_id = $video
        ->getReferenceId())) {
        $video_entity
          ->setReferenceId($reference_id);
      }

      // Save or update custom field values.
      if ($video_entity
        ->getCustomFieldValues() != ($custom_fields = $video
        ->getCustomFields())) {
        $video_entity
          ->setCustomFieldValues($custom_fields);
      }

      // Save or update schedule dates if needed.
      $schedule = $video
        ->getSchedule();
      if (!is_null($schedule)) {
        if ($video_entity
          ->getScheduleStartsAt() != ($starts_at = $schedule
          ->getStartsAt())) {
          $video_entity
            ->setScheduleStartsAt(BrightcoveUtil::convertDate($starts_at));
        }
        if ($video_entity
          ->getScheduleEndsAt() != ($ends_at = $schedule
          ->getEndsAt())) {
          $video_entity
            ->setScheduleEndsAt(BrightcoveUtil::convertDate($ends_at));
        }
      }
      else {
        $video_entity
          ->setScheduleStartsAt(NULL);
        $video_entity
          ->setScheduleEndsAt(NULL);
      }

      // Save or update state.
      // We are settings the video as published only if the state is ACTIVE,
      // otherwise it is set as unpublished.
      $state = $video
        ->getState() == self::STATE_ACTIVE ? TRUE : FALSE;
      if ($video_entity
        ->isPublished() != $state) {
        $video_entity
          ->setPublished($state);
      }

      // Save video entity.
      $video_entity
        ->save();
    }
    return $video_entity;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
BrightcoveCmsEntity::getApiClient public function Returns the Brightcove Client API target ID. Overrides BrightcoveCMSEntityInterface::getApiClient
BrightcoveCmsEntity::getCreatedTime public function Gets the Brightcove CMS entity creation timestamp. Overrides BrightcoveCMSEntityInterface::getCreatedTime
BrightcoveCmsEntity::getCurrentUserId public static function Default value callback for 'uid' base field definition.
BrightcoveCmsEntity::getDescription public function Returns the description. Overrides BrightcoveCMSEntityInterface::getDescription
BrightcoveCmsEntity::getName public function Gets the Brightcove CMS entity name. Overrides BrightcoveCMSEntityInterface::getName
BrightcoveCmsEntity::getOwner public function Returns the entity owner's user entity. Overrides EntityOwnerInterface::getOwner
BrightcoveCmsEntity::getOwnerId public function Returns the entity owner's user ID. Overrides EntityOwnerInterface::getOwnerId
BrightcoveCmsEntity::loadMultipleByApiClient public static function Load multiple CMS Entity for the given api client.
BrightcoveCmsEntity::preCreate public static function Changes the values of an entity before it is created. Overrides EntityBase::preCreate
BrightcoveCmsEntity::preSave public function Acts on an entity before the presave hook is invoked. Overrides ContentEntityBase::preSave
BrightcoveCmsEntity::setApiClient public function Sets the Brightcove Client API target ID. Overrides BrightcoveCMSEntityInterface::setApiClient
BrightcoveCmsEntity::setCreatedTime public function Sets the Brightcove CMS entity creation timestamp. Overrides BrightcoveCMSEntityInterface::setCreatedTime
BrightcoveCmsEntity::setDescription public function Sets the CMS entity's description. Overrides BrightcoveCMSEntityInterface::setDescription
BrightcoveCmsEntity::setName public function Sets the Brightcove CMS entity name. Overrides BrightcoveCMSEntityInterface::setName
BrightcoveCmsEntity::setOwner public function Sets the entity owner's user entity. Overrides EntityOwnerInterface::setOwner
BrightcoveCmsEntity::setOwnerId public function Sets the entity owner's user ID. Overrides EntityOwnerInterface::setOwnerId
BrightcoveVideo::$ingestRequest protected property Ingestion request object.
BrightcoveVideo::baseFieldDefinitions public static function Provides base field definitions for an entity type. Overrides ContentEntityBase::baseFieldDefinitions
BrightcoveVideo::createIngestImage protected function Create an ingestion request for image.
BrightcoveVideo::createOrUpdate public static function Create or update an existing video from a Brightcove Video object.
BrightcoveVideo::delete public function Overrides EntityBase::delete
BrightcoveVideo::deleteFile private function Helper function to delete a file from the entity.
BrightcoveVideo::getBrightcoveId public function Returns the Brightcove ID. Overrides BrightcoveVideoPlaylistCMSEntityInterface::getBrightcoveId
BrightcoveVideo::getCustomFieldValues public function Returns the custom field values. Overrides BrightcoveVideoInterface::getCustomFieldValues
BrightcoveVideo::getDuration public function Returns the video's duration. Overrides BrightcoveVideoInterface::getDuration
BrightcoveVideo::getEconomics public function Returns the economics state. Overrides BrightcoveVideoInterface::getEconomics
BrightcoveVideo::getIngestionToken protected function Get a random hash token for ingestion request callback.
BrightcoveVideo::getIngestRequest protected function Create or get an existing ingestion request object.
BrightcoveVideo::getLongDescription public function Returns the long description of the video. Overrides BrightcoveVideoInterface::getLongDescription
BrightcoveVideo::getPoster public function Returns the video's poster image. Overrides BrightcoveVideoInterface::getPoster
BrightcoveVideo::getProfile public function Returns the video's profile. Overrides BrightcoveVideoInterface::getProfile
BrightcoveVideo::getProfileAllowedValues public static function Gets the allowed values for video profile.
BrightcoveVideo::getRelatedLink public function Returns the video's related link. Overrides BrightcoveVideoInterface::getRelatedLink
BrightcoveVideo::getScheduleEndsAt public function Returns the schedule ends at date. Overrides BrightcoveVideoInterface::getScheduleEndsAt
BrightcoveVideo::getScheduleStartsAt public function Returns the schedule starts at date. Overrides BrightcoveVideoInterface::getScheduleStartsAt
BrightcoveVideo::getTextTracks public function
BrightcoveVideo::getThumbnail public function Returns the video's thumbnail image. Overrides BrightcoveVideoInterface::getThumbnail
BrightcoveVideo::getVideoFile public function Returns the video file. Overrides BrightcoveVideoInterface::getVideoFile
BrightcoveVideo::getVideoUrl public function Returns the video URL. Overrides BrightcoveVideoInterface::getVideoUrl
BrightcoveVideo::loadByBrightcoveVideoId public static function Loads a Video based on the Brightcove Video ID and Account ID.
BrightcoveVideo::profileAllowedValues public static function Implements callback_allowed_values_function().
BrightcoveVideo::provideDefaultValuesForImageField protected function Helper function to provide default values for image fields.
BrightcoveVideo::save public function Overrides EntityBase::save
BrightcoveVideo::saveImage public function Helper function to save the image for the entity. Overrides BrightcoveVideoInterface::saveImage
BrightcoveVideo::setBrightcoveId public function Sets The Brightcove ID. Overrides BrightcoveVideoPlaylistCMSEntityInterface::setBrightcoveId
BrightcoveVideo::setCustomFieldValues public function Sets the custom field values. Overrides BrightcoveVideoInterface::setCustomFieldValues
BrightcoveVideo::setDuration public function Sets the video duration. Overrides BrightcoveVideoInterface::setDuration
BrightcoveVideo::setEconomics public function Sets the video's economics state. Overrides BrightcoveVideoInterface::setEconomics
BrightcoveVideo::setLongDescription public function Sets the video's long description. Overrides BrightcoveVideoInterface::setLongDescription
BrightcoveVideo::setPoster public function Sets the video's poster image. Overrides BrightcoveVideoInterface::setPoster
BrightcoveVideo::setProfile public function Sets the video's profile. Overrides BrightcoveVideoInterface::setProfile
BrightcoveVideo::setRelatedLink public function Sets the video's related link. Overrides BrightcoveVideoInterface::setRelatedLink
BrightcoveVideo::setScheduleEndsAt public function Sets the video's schedule ends at date. Overrides BrightcoveVideoInterface::setScheduleEndsAt
BrightcoveVideo::setScheduleStartsAt public function Sets the video's schedule starts at date. Overrides BrightcoveVideoInterface::setScheduleStartsAt
BrightcoveVideo::setTextTracks public function
BrightcoveVideo::setThumbnail public function Sets the video's thumbnail image. Overrides BrightcoveVideoInterface::setThumbnail
BrightcoveVideo::setVideoFile public function Sets the video file. Overrides BrightcoveVideoInterface::setVideoFile
BrightcoveVideo::setVideoUrl public function Sets the video URL. Overrides BrightcoveVideoInterface::setVideoUrl
BrightcoveVideoInterface::ECONOMICS_TYPE_AD_SUPPORTED constant Brightcove economics type, ad supported.
BrightcoveVideoInterface::ECONOMICS_TYPE_FREE constant Brightcove economics type, free.
BrightcoveVideoInterface::IMAGE_TYPE_POSTER constant Brightcove poster image type.
BrightcoveVideoInterface::IMAGE_TYPE_THUMBNAIL constant Brightcove thumbnail image type.
BrightcoveVideoInterface::NOT_PUBLISHED constant Denotes that the video is not published.
BrightcoveVideoInterface::PUBLISHED constant Denotes that the video is published.
BrightcoveVideoInterface::STATE_ACTIVE constant Brightcove active state.
BrightcoveVideoInterface::STATE_INACTIVE constant Brightcove inactive state.
BrightcoveVideoInterface::TAGS_VID constant Brightcove video tags vocabulary ID.
BrightcoveVideoInterface::VIDEOS_IMAGES_POSTERS_DIR constant Brightcove video poster images path.
BrightcoveVideoInterface::VIDEOS_IMAGES_THUMBNAILS_DIR constant Brightcove video thumbnail images path.
BrightcoveVideoPlaylistCmsEntity::getDefaultReferenceId public static function Default value callback for 'reference_id' base field definition.
BrightcoveVideoPlaylistCmsEntity::getPlayer public function Returns the player. Overrides BrightcoveVideoPlaylistCMSEntityInterface::getPlayer
BrightcoveVideoPlaylistCmsEntity::getReferenceId public function Returns the reference ID. Overrides BrightcoveVideoPlaylistCMSEntityInterface::getReferenceId
BrightcoveVideoPlaylistCmsEntity::getTags public function Returns the tags. Overrides BrightcoveVideoPlaylistCMSEntityInterface::getTags
BrightcoveVideoPlaylistCmsEntity::isPublished public function Returns the entity published status indicator. Overrides BrightcoveVideoPlaylistCMSEntityInterface::isPublished
BrightcoveVideoPlaylistCmsEntity::setPlayer public function Sets the player. Overrides BrightcoveVideoPlaylistCMSEntityInterface::setPlayer
BrightcoveVideoPlaylistCmsEntity::setPublished public function Sets the published status of the entity. Overrides BrightcoveVideoPlaylistCMSEntityInterface::setPublished
BrightcoveVideoPlaylistCmsEntity::setReferenceId public function Sets the reference ID. Overrides BrightcoveVideoPlaylistCMSEntityInterface::setReferenceId
BrightcoveVideoPlaylistCmsEntity::setTags public function Sets the tags. Overrides BrightcoveVideoPlaylistCMSEntityInterface::setTags
CacheableDependencyTrait::$cacheContexts protected property Cache contexts.
CacheableDependencyTrait::$cacheMaxAge protected property Cache max-age.
CacheableDependencyTrait::$cacheTags protected property Cache tags.
CacheableDependencyTrait::setCacheability protected function Sets cacheability; useful for value object constructors.
ContentEntityBase::$activeLangcode protected property Language code identifying the entity active language.
ContentEntityBase::$defaultLangcode protected property Local cache for the default language code.
ContentEntityBase::$defaultLangcodeKey protected property The default langcode entity key.
ContentEntityBase::$enforceRevisionTranslationAffected protected property Whether the revision translation affected flag has been enforced.
ContentEntityBase::$entityKeys protected property Holds untranslatable entity keys such as the ID, bundle, and revision ID.
ContentEntityBase::$fieldDefinitions protected property Local cache for field definitions.
ContentEntityBase::$fields protected property The array of fields, each being an instance of FieldItemListInterface.
ContentEntityBase::$fieldsToSkipFromTranslationChangesCheck protected static property Local cache for fields to skip from the checking for translation changes.
ContentEntityBase::$isDefaultRevision protected property Indicates whether this is the default revision.
ContentEntityBase::$langcodeKey protected property The language entity key.
ContentEntityBase::$languages protected property Local cache for the available language objects.
ContentEntityBase::$loadedRevisionId protected property The loaded revision ID before the new revision was set.
ContentEntityBase::$newRevision protected property Boolean indicating whether a new revision should be created on save.
ContentEntityBase::$revisionTranslationAffectedKey protected property The revision translation affected entity key.
ContentEntityBase::$translatableEntityKeys protected property Holds translatable entity keys such as the label.
ContentEntityBase::$translationInitialize protected property A flag indicating whether a translation object is being initialized.
ContentEntityBase::$translations protected property An array of entity translation metadata.
ContentEntityBase::$validated protected property Whether entity validation was performed.
ContentEntityBase::$validationRequired protected property Whether entity validation is required before saving the entity.
ContentEntityBase::$values protected property The plain data values of the contained fields.
ContentEntityBase::access public function Checks data value access. Overrides EntityBase::access 1
ContentEntityBase::addTranslation public function Adds a new translation to the translatable object. Overrides TranslatableInterface::addTranslation
ContentEntityBase::bundle public function Gets the bundle of the entity. Overrides EntityBase::bundle
ContentEntityBase::bundleFieldDefinitions public static function Provides field definitions for a specific bundle. Overrides FieldableEntityInterface::bundleFieldDefinitions 4
ContentEntityBase::clearTranslationCache protected function Clear entity translation object cache to remove stale references.
ContentEntityBase::createDuplicate public function Creates a duplicate of the entity. Overrides EntityBase::createDuplicate 1
ContentEntityBase::get public function Gets a field item list. Overrides FieldableEntityInterface::get
ContentEntityBase::getEntityKey protected function Gets the value of the given entity key, if defined. 1
ContentEntityBase::getFieldDefinition public function Gets the definition of a contained field. Overrides FieldableEntityInterface::getFieldDefinition
ContentEntityBase::getFieldDefinitions public function Gets an array of field definitions of all contained fields. Overrides FieldableEntityInterface::getFieldDefinitions
ContentEntityBase::getFields public function Gets an array of all field item lists. Overrides FieldableEntityInterface::getFields
ContentEntityBase::getFieldsToSkipFromTranslationChangesCheck protected function Returns an array of field names to skip in ::hasTranslationChanges. 1
ContentEntityBase::getIterator public function
ContentEntityBase::getLanguages protected function
ContentEntityBase::getLoadedRevisionId public function Gets the loaded Revision ID of the entity. Overrides RevisionableInterface::getLoadedRevisionId
ContentEntityBase::getRevisionId public function Gets the revision identifier of the entity. Overrides RevisionableInterface::getRevisionId
ContentEntityBase::getTranslatableFields public function Gets an array of field item lists for translatable fields. Overrides FieldableEntityInterface::getTranslatableFields
ContentEntityBase::getTranslatedField protected function Gets a translated field.
ContentEntityBase::getTranslation public function Gets a translation of the data. Overrides TranslatableInterface::getTranslation
ContentEntityBase::getTranslationLanguages public function Returns the languages the data is translated to. Overrides TranslatableInterface::getTranslationLanguages
ContentEntityBase::getTranslationStatus public function Returns the translation status. Overrides TranslationStatusInterface::getTranslationStatus
ContentEntityBase::getUntranslated public function Returns the translatable object referring to the original language. Overrides TranslatableInterface::getUntranslated
ContentEntityBase::hasField public function Determines whether the entity has a field with the given name. Overrides FieldableEntityInterface::hasField
ContentEntityBase::hasTranslation public function Checks there is a translation for the given language code. Overrides TranslatableInterface::hasTranslation
ContentEntityBase::hasTranslationChanges public function Determines if the current translation of the entity has unsaved changes. Overrides TranslatableInterface::hasTranslationChanges
ContentEntityBase::id public function Gets the identifier. Overrides EntityBase::id
ContentEntityBase::initializeTranslation protected function Instantiates a translation object for an existing translation.
ContentEntityBase::isDefaultRevision public function Checks if this entity is the default revision. Overrides RevisionableInterface::isDefaultRevision
ContentEntityBase::isDefaultTranslation public function Checks whether the translation is the default one. Overrides TranslatableInterface::isDefaultTranslation
ContentEntityBase::isDefaultTranslationAffectedOnly public function Checks if untranslatable fields should affect only the default translation. Overrides TranslatableRevisionableInterface::isDefaultTranslationAffectedOnly
ContentEntityBase::isLatestRevision public function Checks if this entity is the latest revision. Overrides RevisionableInterface::isLatestRevision
ContentEntityBase::isLatestTranslationAffectedRevision public function Checks whether this is the latest revision affecting this translation. Overrides TranslatableRevisionableInterface::isLatestTranslationAffectedRevision
ContentEntityBase::isNewRevision public function Determines whether a new revision should be created on save. Overrides RevisionableInterface::isNewRevision
ContentEntityBase::isNewTranslation public function Checks whether the translation is new. Overrides TranslatableInterface::isNewTranslation
ContentEntityBase::isRevisionTranslationAffected public function Checks whether the current translation is affected by the current revision. Overrides TranslatableRevisionableInterface::isRevisionTranslationAffected
ContentEntityBase::isRevisionTranslationAffectedEnforced public function Checks if the revision translation affected flag value has been enforced. Overrides TranslatableRevisionableInterface::isRevisionTranslationAffectedEnforced
ContentEntityBase::isTranslatable public function Returns the translation support status. Overrides TranslatableInterface::isTranslatable
ContentEntityBase::isValidationRequired public function Checks whether entity validation is required before saving the entity. Overrides FieldableEntityInterface::isValidationRequired
ContentEntityBase::label public function Gets the label of the entity. Overrides EntityBase::label 6
ContentEntityBase::language public function Gets the language of the entity. Overrides EntityBase::language
ContentEntityBase::onChange public function Reacts to changes to a field. Overrides FieldableEntityInterface::onChange
ContentEntityBase::postCreate public function Acts on a created entity before hooks are invoked. Overrides EntityBase::postCreate
ContentEntityBase::postSave public function Acts on a saved entity before the insert or update hook is invoked. Overrides EntityBase::postSave 9
ContentEntityBase::preSaveRevision public function Acts on a revision before it gets saved. Overrides RevisionableInterface::preSaveRevision 3
ContentEntityBase::referencedEntities public function Gets a list of entities referenced by this entity. Overrides EntityBase::referencedEntities 1
ContentEntityBase::removeTranslation public function Removes the translation identified by the given language code. Overrides TranslatableInterface::removeTranslation
ContentEntityBase::set public function Sets a field value. Overrides FieldableEntityInterface::set
ContentEntityBase::setDefaultLangcode protected function Populates the local cache for the default language code.
ContentEntityBase::setNewRevision public function Enforces an entity to be saved as a new revision. Overrides RevisionableInterface::setNewRevision
ContentEntityBase::setRevisionTranslationAffected public function Marks the current revision translation as affected. Overrides TranslatableRevisionableInterface::setRevisionTranslationAffected
ContentEntityBase::setRevisionTranslationAffectedEnforced public function Enforces the revision translation affected flag value. Overrides TranslatableRevisionableInterface::setRevisionTranslationAffectedEnforced
ContentEntityBase::setValidationRequired public function Sets whether entity validation is required before saving the entity. Overrides FieldableEntityInterface::setValidationRequired
ContentEntityBase::toArray public function Gets an array of all property values. Overrides EntityBase::toArray
ContentEntityBase::updateFieldLangcodes protected function Updates language for already instantiated fields.
ContentEntityBase::updateLoadedRevisionId public function Updates the loaded Revision ID with the revision ID. Overrides RevisionableInterface::updateLoadedRevisionId
ContentEntityBase::updateOriginalValues public function Updates the original values with the interim changes.
ContentEntityBase::uuid public function Gets the entity UUID (Universally Unique Identifier). Overrides EntityBase::uuid
ContentEntityBase::validate public function Validates the currently set values. Overrides FieldableEntityInterface::validate 1
ContentEntityBase::wasDefaultRevision public function Checks whether the entity object was a default revision when it was saved. Overrides RevisionableInterface::wasDefaultRevision
ContentEntityBase::__clone public function Magic method: Implements a deep clone.
ContentEntityBase::__construct public function Constructs an Entity object. Overrides EntityBase::__construct
ContentEntityBase::__get public function Implements the magic method for getting object properties.
ContentEntityBase::__isset public function Implements the magic method for isset().
ContentEntityBase::__set public function Implements the magic method for setting object properties.
ContentEntityBase::__sleep public function Overrides EntityBase::__sleep
ContentEntityBase::__unset public function Implements the magic method for unset().
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function Aliased as: traitSleep 2
DependencySerializationTrait::__wakeup public function 2
EntityBase::$enforceIsNew protected property Boolean indicating whether the entity should be forced to be new.
EntityBase::$entityTypeId protected property The entity type.
EntityBase::$typedData protected property A typed data object wrapping this entity.
EntityBase::create public static function Constructs a new entity object, without permanently saving it. Overrides EntityInterface::create
EntityBase::enforceIsNew public function Enforces an entity to be new. Overrides EntityInterface::enforceIsNew
EntityBase::entityTypeBundleInfo protected function Gets the entity type bundle info service.
EntityBase::entityTypeManager protected function Gets the entity type manager.
EntityBase::getCacheContexts public function The cache contexts associated with this object. Overrides CacheableDependencyTrait::getCacheContexts
EntityBase::getCacheMaxAge public function The maximum age for which this object may be cached. Overrides CacheableDependencyTrait::getCacheMaxAge
EntityBase::getCacheTags public function The cache tags associated with this object. Overrides CacheableDependencyTrait::getCacheTags
EntityBase::getCacheTagsToInvalidate public function Returns the cache tags that should be used to invalidate caches. Overrides EntityInterface::getCacheTagsToInvalidate 4
EntityBase::getConfigDependencyKey public function Gets the key that is used to store configuration dependencies. Overrides EntityInterface::getConfigDependencyKey
EntityBase::getConfigDependencyName public function Gets the configuration dependency name. Overrides EntityInterface::getConfigDependencyName 1
EntityBase::getConfigTarget public function Gets the configuration target identifier for the entity. Overrides EntityInterface::getConfigTarget 1
EntityBase::getEntityType public function Gets the entity type definition. Overrides EntityInterface::getEntityType
EntityBase::getEntityTypeId public function Gets the ID of the type of the entity. Overrides EntityInterface::getEntityTypeId
EntityBase::getListCacheTagsToInvalidate protected function The list cache tags to invalidate for this entity.
EntityBase::getOriginalId public function Gets the original ID. Overrides EntityInterface::getOriginalId 1
EntityBase::getTypedData public function Gets a typed data object for this entity object. Overrides EntityInterface::getTypedData
EntityBase::hasLinkTemplate public function Indicates if a link template exists for a given key. Overrides EntityInterface::hasLinkTemplate
EntityBase::invalidateTagsOnDelete protected static function Invalidates an entity's cache tags upon delete. 1
EntityBase::invalidateTagsOnSave protected function Invalidates an entity's cache tags upon save. 1
EntityBase::isNew public function Determines whether the entity is new. Overrides EntityInterface::isNew 2
EntityBase::languageManager protected function Gets the language manager.
EntityBase::linkTemplates protected function Gets an array link templates. 1
EntityBase::load public static function Loads an entity. Overrides EntityInterface::load
EntityBase::loadMultiple public static function Loads one or more entities. Overrides EntityInterface::loadMultiple
EntityBase::postDelete public static function Acts on deleted entities before the delete hook is invoked. Overrides EntityInterface::postDelete 18
EntityBase::postLoad public static function Acts on loaded entities. Overrides EntityInterface::postLoad 2
EntityBase::preDelete public static function Acts on entities before they are deleted and before hooks are invoked. Overrides EntityInterface::preDelete 6
EntityBase::setOriginalId public function Sets the original ID. Overrides EntityInterface::setOriginalId 1
EntityBase::toLink public function Generates the HTML for a link to this entity. Overrides EntityInterface::toLink
EntityBase::toUrl public function Gets the URL object for the entity. Overrides EntityInterface::toUrl 2
EntityBase::uriRelationships public function Gets a list of URI relationships supported by this entity. Overrides EntityInterface::uriRelationships
EntityBase::urlRouteParameters protected function Gets an array of placeholders for this entity. 2
EntityBase::uuidGenerator protected function Gets the UUID generator.
EntityChangedFieldsTrait::$changedFields protected property Changed fields.
EntityChangedFieldsTrait::$hasChangedField protected property Has changed field or not.
EntityChangedFieldsTrait::checkUpdatedFields public function Check for updated fields.
EntityChangedFieldsTrait::getGetterName public function Get getter method from the name of the field.
EntityChangedFieldsTrait::hasChangedField public function Checked if the Entity has a changed field or not.
EntityChangedFieldsTrait::isFieldChanged public function Returns whether the field is changed or not.
EntityChangedTrait::getChangedTime public function Gets the timestamp of the last entity change for the current translation.
EntityChangedTrait::getChangedTimeAcrossTranslations public function Returns the timestamp of the last entity change across all translations.
EntityChangedTrait::setChangedTime public function Sets the timestamp of the last entity change for the current translation.
EntityChangesDetectionTrait::getFieldsToSkipFromTranslationChangesCheck protected function Returns an array of field names to skip when checking for changes. Aliased as: traitGetFieldsToSkipFromTranslationChangesCheck
RefinableCacheableDependencyTrait::addCacheableDependency public function 1
RefinableCacheableDependencyTrait::addCacheContexts public function
RefinableCacheableDependencyTrait::addCacheTags public function
RefinableCacheableDependencyTrait::mergeCacheMaxAge public function
SynchronizableEntityTrait::$isSyncing protected property Whether this entity is being created, updated or deleted through a synchronization process.
SynchronizableEntityTrait::isSyncing public function
SynchronizableEntityTrait::setSyncing public function
TranslationStatusInterface::TRANSLATION_CREATED constant Status code identifying a newly created translation.
TranslationStatusInterface::TRANSLATION_EXISTING constant Status code identifying an existing translation.
TranslationStatusInterface::TRANSLATION_REMOVED constant Status code identifying a removed translation.