Chris@0: get('name'); Chris@0: Chris@0: if ($name->isEmpty()) { Chris@0: $media_source = $this->getSource(); Chris@0: return $media_source->getMetadata($this, $media_source->getPluginDefinition()['default_name_metadata_attribute']); Chris@0: } Chris@0: else { Chris@0: return $name->value; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function label() { Chris@0: return $this->getName(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setName($name) { Chris@0: return $this->set('name', $name); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getCreatedTime() { Chris@0: return $this->get('created')->value; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setCreatedTime($timestamp) { Chris@0: return $this->set('created', $timestamp); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getOwner() { Chris@0: return $this->get('uid')->entity; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setOwner(UserInterface $account) { Chris@0: return $this->set('uid', $account->id()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getOwnerId() { Chris@0: return $this->get('uid')->target_id; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setOwnerId($uid) { Chris@0: return $this->set('uid', $uid); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getSource() { Chris@0: return $this->bundle->entity->getSource(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Update the thumbnail for the media item. Chris@0: * Chris@0: * @param bool $from_queue Chris@0: * Specifies whether the thumbnail update is triggered from the queue. Chris@0: * Chris@0: * @return \Drupal\media\MediaInterface Chris@0: * The updated media item. Chris@0: * Chris@0: * @internal Chris@0: * Chris@0: * @todo There has been some disagreement about how to handle updates to Chris@0: * thumbnails. We need to decide on what the API will be for this. Chris@0: * https://www.drupal.org/node/2878119 Chris@0: */ Chris@0: protected function updateThumbnail($from_queue = FALSE) { Chris@0: $file_storage = \Drupal::service('entity_type.manager')->getStorage('file'); Chris@0: $thumbnail_uri = $this->getThumbnailUri($from_queue); Chris@0: $existing = $file_storage->getQuery() Chris@0: ->condition('uri', $thumbnail_uri) Chris@0: ->execute(); Chris@0: Chris@0: if ($existing) { Chris@0: $this->thumbnail->target_id = reset($existing); Chris@0: } Chris@0: else { Chris@0: /** @var \Drupal\file\FileInterface $file */ Chris@0: $file = $file_storage->create(['uri' => $thumbnail_uri]); Chris@0: if ($owner = $this->getOwner()) { Chris@0: $file->setOwner($owner); Chris@0: } Chris@0: $file->setPermanent(); Chris@0: $file->save(); Chris@0: $this->thumbnail->target_id = $file->id(); Chris@0: } Chris@0: Chris@0: // Set the thumbnail alt. Chris@0: $media_source = $this->getSource(); Chris@0: $plugin_definition = $media_source->getPluginDefinition(); Chris@0: if (!empty($plugin_definition['thumbnail_alt_metadata_attribute'])) { Chris@0: $this->thumbnail->alt = $media_source->getMetadata($this, $plugin_definition['thumbnail_alt_metadata_attribute']); Chris@0: } Chris@0: else { Chris@0: $this->thumbnail->alt = $this->t('Thumbnail', [], ['langcode' => $this->langcode->value]); Chris@0: } Chris@0: Chris@0: // Set the thumbnail title. Chris@0: if (!empty($plugin_definition['thumbnail_title_metadata_attribute'])) { Chris@0: $this->thumbnail->title = $media_source->getMetadata($this, $plugin_definition['thumbnail_title_metadata_attribute']); Chris@0: } Chris@0: else { Chris@0: $this->thumbnail->title = $this->label(); Chris@0: } Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Updates the queued thumbnail for the media item. Chris@0: * Chris@0: * @return \Drupal\media\MediaInterface Chris@0: * The updated media item. Chris@0: * Chris@0: * @internal Chris@0: * Chris@0: * @todo If the need arises in contrib, consider making this a public API, Chris@0: * by adding an interface that extends MediaInterface. Chris@0: */ Chris@0: public function updateQueuedThumbnail() { Chris@0: $this->updateThumbnail(TRUE); Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the URI for the thumbnail of a media item. Chris@0: * Chris@0: * If thumbnail fetching is queued, new media items will use the default Chris@0: * thumbnail, and existing media items will use the current thumbnail, until Chris@0: * the queue is processed and the updated thumbnail has been fetched. Chris@0: * Otherwise, the new thumbnail will be fetched immediately. Chris@0: * Chris@0: * @param bool $from_queue Chris@0: * Specifies whether the thumbnail is being fetched from the queue. Chris@0: * Chris@0: * @return string Chris@0: * The file URI for the thumbnail of the media item. Chris@0: * Chris@0: * @internal Chris@0: */ Chris@0: protected function getThumbnailUri($from_queue) { Chris@0: $thumbnails_queued = $this->bundle->entity->thumbnailDownloadsAreQueued(); Chris@0: if ($thumbnails_queued && $this->isNew()) { Chris@0: $default_thumbnail_filename = $this->getSource()->getPluginDefinition()['default_thumbnail_filename']; Chris@0: $thumbnail_uri = \Drupal::service('config.factory')->get('media.settings')->get('icon_base_uri') . '/' . $default_thumbnail_filename; Chris@0: } Chris@0: elseif ($thumbnails_queued && !$from_queue) { Chris@0: $thumbnail_uri = $this->get('thumbnail')->entity->getFileUri(); Chris@0: } Chris@0: else { Chris@0: $thumbnail_uri = $this->getSource()->getMetadata($this, $this->getSource()->getPluginDefinition()['thumbnail_uri_metadata_attribute']); Chris@0: } Chris@0: Chris@0: return $thumbnail_uri; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines if the source field value has changed. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the source field value changed, FALSE otherwise. Chris@0: * Chris@0: * @internal Chris@0: */ Chris@0: protected function hasSourceFieldChanged() { Chris@0: $source_field_name = $this->getSource()->getConfiguration()['source_field']; Chris@0: $current_items = $this->get($source_field_name); Chris@0: return isset($this->original) && !$current_items->equals($this->original->get($source_field_name)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines if the thumbnail should be updated for a media item. Chris@0: * Chris@0: * @param bool $is_new Chris@0: * Specifies whether the media item is new. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the thumbnail should be updated, FALSE otherwise. Chris@0: */ Chris@0: protected function shouldUpdateThumbnail($is_new = FALSE) { Chris@0: // Update thumbnail if we don't have a thumbnail yet or when the source Chris@0: // field value changes. Chris@0: return !$this->get('thumbnail')->entity || $is_new || $this->hasSourceFieldChanged(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function preSave(EntityStorageInterface $storage) { Chris@0: parent::preSave($storage); Chris@0: Chris@0: $media_source = $this->getSource(); Chris@0: foreach ($this->translations as $langcode => $data) { Chris@0: if ($this->hasTranslation($langcode)) { Chris@0: $translation = $this->getTranslation($langcode); Chris@0: // Try to set fields provided by the media source and mapped in Chris@0: // media type config. Chris@0: foreach ($translation->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) { Chris@0: // Only save value in entity field if empty. Do not overwrite existing Chris@0: // data. Chris@0: if ($translation->hasField($entity_field_name) && ($translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged())) { Chris@0: $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name)); Chris@0: } Chris@0: } Chris@0: Chris@0: // Try to set a default name for this media item if no name is provided. Chris@0: if ($translation->get('name')->isEmpty()) { Chris@0: $translation->setName($translation->getName()); Chris@0: } Chris@0: Chris@0: // Set thumbnail. Chris@0: if ($translation->shouldUpdateThumbnail()) { Chris@0: $translation->updateThumbnail(); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function postSave(EntityStorageInterface $storage, $update = TRUE) { Chris@0: parent::postSave($storage, $update); Chris@0: $is_new = !$update; Chris@0: foreach ($this->translations as $langcode => $data) { Chris@0: if ($this->hasTranslation($langcode)) { Chris@0: $translation = $this->getTranslation($langcode); Chris@0: if ($translation->bundle->entity->thumbnailDownloadsAreQueued() && $translation->shouldUpdateThumbnail($is_new)) { Chris@0: \Drupal::queue('media_entity_thumbnail')->createItem(['id' => $translation->id()]); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) { Chris@0: parent::preSaveRevision($storage, $record); Chris@0: Chris@0: $is_new_revision = $this->isNewRevision(); Chris@0: if (!$is_new_revision && isset($this->original) && empty($record->revision_log_message)) { Chris@0: // If we are updating an existing media item without adding a Chris@0: // new revision, we need to make sure $entity->revision_log_message is Chris@0: // reset whenever it is empty. Chris@0: // Therefore, this code allows us to avoid clobbering an existing log Chris@0: // entry with an empty one. Chris@0: $record->revision_log_message = $this->original->revision_log_message->value; Chris@0: } Chris@0: Chris@0: if ($is_new_revision) { Chris@0: $record->revision_created = self::getRequestTime(); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function validate() { Chris@0: $media_source = $this->getSource(); Chris@0: Chris@0: if ($media_source instanceof MediaSourceEntityConstraintsInterface) { Chris@0: $entity_constraints = $media_source->getEntityConstraints(); Chris@0: $this->getTypedData()->getDataDefinition()->setConstraints($entity_constraints); Chris@0: } Chris@0: Chris@0: if ($media_source instanceof MediaSourceFieldConstraintsInterface) { Chris@0: $source_field_name = $media_source->getConfiguration()['source_field']; Chris@0: $source_field_constraints = $media_source->getSourceFieldConstraints(); Chris@0: $this->get($source_field_name)->getDataDefinition()->setConstraints($source_field_constraints); Chris@0: } Chris@0: Chris@0: return parent::validate(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { Chris@0: $fields = parent::baseFieldDefinitions($entity_type); Chris@0: Chris@0: $fields['name'] = BaseFieldDefinition::create('string') Chris@0: ->setLabel(t('Name')) Chris@0: ->setRequired(TRUE) Chris@0: ->setTranslatable(TRUE) Chris@0: ->setRevisionable(TRUE) Chris@0: ->setDefaultValue('') Chris@0: ->setSetting('max_length', 255) Chris@0: ->setDisplayOptions('form', [ Chris@0: 'type' => 'string_textfield', Chris@0: 'weight' => -5, Chris@0: ]) Chris@0: ->setDisplayConfigurable('form', TRUE) Chris@0: ->setDisplayOptions('view', [ Chris@0: 'label' => 'hidden', Chris@0: 'type' => 'string', Chris@0: 'weight' => -5, Chris@0: ]); Chris@0: Chris@0: $fields['thumbnail'] = BaseFieldDefinition::create('image') Chris@0: ->setLabel(t('Thumbnail')) Chris@0: ->setDescription(t('The thumbnail of the media item.')) Chris@0: ->setRevisionable(TRUE) Chris@0: ->setTranslatable(TRUE) Chris@0: ->setDisplayOptions('view', [ Chris@0: 'type' => 'image', Chris@0: 'weight' => 5, Chris@0: 'label' => 'hidden', Chris@0: 'settings' => [ Chris@0: 'image_style' => 'thumbnail', Chris@0: ], Chris@0: ]) Chris@0: ->setDisplayConfigurable('view', TRUE) Chris@0: ->setReadOnly(TRUE); Chris@0: Chris@0: $fields['uid'] = BaseFieldDefinition::create('entity_reference') Chris@0: ->setLabel(t('Authored by')) Chris@0: ->setDescription(t('The user ID of the author.')) Chris@0: ->setRevisionable(TRUE) Chris@0: ->setDefaultValueCallback(static::class . '::getCurrentUserId') Chris@0: ->setSetting('target_type', 'user') Chris@0: ->setTranslatable(TRUE) Chris@0: ->setDisplayOptions('form', [ Chris@0: 'type' => 'entity_reference_autocomplete', Chris@0: 'weight' => 5, Chris@0: 'settings' => [ Chris@0: 'match_operator' => 'CONTAINS', Chris@0: 'size' => '60', Chris@0: 'autocomplete_type' => 'tags', Chris@0: 'placeholder' => '', Chris@0: ], Chris@0: ]) Chris@0: ->setDisplayConfigurable('form', TRUE) Chris@0: ->setDisplayOptions('view', [ Chris@0: 'label' => 'hidden', Chris@0: 'type' => 'author', Chris@0: 'weight' => 0, Chris@0: ]) Chris@0: ->setDisplayConfigurable('view', TRUE); Chris@0: Chris@0: $fields['status'] Chris@0: ->setDisplayOptions('form', [ Chris@0: 'type' => 'boolean_checkbox', Chris@0: 'settings' => [ Chris@0: 'display_label' => TRUE, Chris@0: ], Chris@0: 'weight' => 100, Chris@0: ]) Chris@0: ->setDisplayConfigurable('form', TRUE); Chris@0: Chris@0: $fields['created'] = BaseFieldDefinition::create('created') Chris@0: ->setLabel(t('Authored on')) Chris@0: ->setDescription(t('The time the media item was created.')) Chris@0: ->setTranslatable(TRUE) Chris@0: ->setRevisionable(TRUE) Chris@0: ->setDefaultValueCallback(static::class . '::getRequestTime') Chris@0: ->setDisplayOptions('form', [ Chris@0: 'type' => 'datetime_timestamp', Chris@0: 'weight' => 10, Chris@0: ]) Chris@0: ->setDisplayConfigurable('form', TRUE) Chris@0: ->setDisplayOptions('view', [ Chris@0: 'label' => 'hidden', Chris@0: 'type' => 'timestamp', Chris@0: 'weight' => 0, Chris@0: ]) Chris@0: ->setDisplayConfigurable('view', TRUE); Chris@0: Chris@0: $fields['changed'] = BaseFieldDefinition::create('changed') Chris@0: ->setLabel(t('Changed')) Chris@0: ->setDescription(t('The time the media item was last edited.')) Chris@0: ->setTranslatable(TRUE) Chris@0: ->setRevisionable(TRUE); Chris@0: Chris@0: return $fields; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Default value callback for 'uid' base field definition. Chris@0: * Chris@0: * @see ::baseFieldDefinitions() Chris@0: * Chris@0: * @return int[] Chris@0: * An array of default values. Chris@0: */ Chris@0: public static function getCurrentUserId() { Chris@0: return [\Drupal::currentUser()->id()]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function getRequestTime() { Chris@0: return \Drupal::time()->getRequestTime(); Chris@0: } Chris@0: Chris@0: }