You are here

public function FileLinkItem::preSave in File Link 2.0.x

Same name and namespace in other branches
  1. 8 src/Plugin/Field/FieldType/FileLinkItem.php \Drupal\file_link\Plugin\Field\FieldType\FileLinkItem::preSave()

Defines custom presave behavior for field values.

This method is called during the process of saving an entity, just before values are written into storage. When storing a new entity, its identifier will not be available yet. This should be used to massage item property values or perform any other operation that needs to happen before values are stored. For instance this is the proper phase to auto-create a new entity for an entity reference field item, because this way it will be possible to store the referenced entity identifier.

Overrides FieldItemBase::preSave

File

src/Plugin/Field/FieldType/FileLinkItem.php, line 181

Class

FileLinkItem
Implements a 'file_link' plugin field type.

Namespace

Drupal\file_link\Plugin\Field\FieldType

Code

public function preSave() {
  parent::preSave();

  // Skip performing HTTP requests, useful when running bulk imports.
  if (Settings::get('file_link.disable_http_requests', FALSE)) {
    return;
  }
  $entity = $this
    ->getEntity();
  $storage = $this
    ->getEntityTypeManager()
    ->getStorage($entity
    ->getEntityTypeId());

  /** @var \Drupal\Core\Entity\ContentEntityInterface $original */
  $original = $entity
    ->isNew() ? NULL : $storage
    ->loadUnchanged($entity
    ->id());
  $field_name = $this
    ->getFieldDefinition()
    ->getName();
  $original_uri = NULL;
  $size = NULL;
  $format = NULL;
  if ($original !== NULL) {
    $item = $original
      ->get($field_name)
      ->get($this
      ->getName());
    if ($item != NULL) {
      $values = $item
        ->getValue();
      $original_uri = $values['uri'];
      $size = $values['size'];
      $format = $values['format'];
    }
  }

  // We parse the metadata in any of the next cases:
  // - The host entity is new.
  // - The 'file_link' URI has changed.
  // - Stored metadata is empty, possible due to an previous failure. We try
  //   again to parse, hoping the connection was fixed in the meantime.
  $this->needsParsing = $entity
    ->isNew() || $this->uri !== $original_uri || empty($size) || empty($format);
  if ($this->needsParsing) {
    if ($this
      ->needsQueue()) {

      // We set the needs_parsing property and check it in ::postSave.
      // Now just reset the values, cron will set them later.
      $this
        ->writePropertyValue('size', NULL);
      $this
        ->writePropertyValue('format', NULL);
      return;
    }

    // Don't throw exceptions on HTTP level errors (e.g. 404, 403, etc).
    $options = [
      'exceptions' => FALSE,
      'allow_redirects' => [
        'strict' => TRUE,
      ],
    ];
    $url = Url::fromUri($this->uri, [
      'absolute' => TRUE,
    ])
      ->toString();

    // Clear any previous stored results (response and/or exception).
    $this
      ->clearResponse();
    $this
      ->clearException();
    try {

      // Perform only a HEAD method to save bandwidth.
      $this
        ->setResponse($this
        ->getHttpClient()
        ->head($url, $options));
    } catch (RequestException $request_exception) {
      $this
        ->setException($request_exception);
    }
    $format = NULL;
    $size = 0;
    if (!$this
      ->getException() && ($response = $this
      ->getResponse()) && $this
      ->isSupportedResponse($response)) {
      if ($response
        ->hasHeader('Content-Type')) {

        // The format may have the pattern 'text/html; charset=UTF-8'. In this
        // case, keep only the first relevant part.
        $format = explode(';', $response
          ->getHeaderLine('Content-Type'))[0];
      }
      else {
        $format = NULL;
      }
      if ($response
        ->hasHeader('Content-Length')) {
        $size = (int) $response
          ->getHeaderLine('Content-Length');
      }
      else {

        // The server didn't sent the Content-Length header. In this case,
        // perform a full GET and measure the size of the returned body.
        $response = $this
          ->getHttpClient()
          ->get($url, $options);
        $size = (int) $response
          ->getBody()
          ->getSize();
        $this
          ->setResponse($response);
      }
      $this
        ->writePropertyValue('size', $size);
      $this
        ->writePropertyValue('format', $format);
    }
  }
}