View source
<?php
namespace Drupal\file_link\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\Url;
use Drupal\file\Plugin\Field\FieldType\FileItem;
use Drupal\file_link\FileLinkInterface;
use Drupal\link\Plugin\Field\FieldType\LinkItem;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Message\ResponseInterface;
class FileLinkItem extends LinkItem implements FileLinkInterface {
protected $response = NULL;
protected $exception = NULL;
protected $entityTypeManager;
protected $httpClient;
public static function defaultFieldSettings() {
return [
'file_extensions' => 'txt',
'no_extension' => FALSE,
] + parent::defaultFieldSettings();
}
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
return parent::propertyDefinitions($field_definition) + [
'size' => DataDefinition::create('integer')
->setLabel(t('Size')),
'format' => DataDefinition::create('string')
->setLabel(t('Format')),
];
}
public static function schema(FieldStorageDefinitionInterface $field_definition) {
$schema = parent::schema($field_definition);
$schema['columns']['size'] = [
'description' => 'The size of the file.',
'type' => 'int',
'size' => 'big',
'unsigned' => TRUE,
];
$schema['columns']['format'] = [
'description' => 'The format of the file.',
'type' => 'varchar',
'length' => 255,
];
$schema['indexes']['size'] = [
'size',
];
$schema['indexes']['format'] = [
'format',
];
return $schema;
}
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
$element = parent::fieldSettingsForm($form, $form_state);
$extensions = str_replace(' ', ', ', $this
->getSetting('file_extensions'));
$element['file_extensions'] = [
'#type' => 'textfield',
'#title' => $this
->t('Allowed file extensions'),
'#default_value' => $extensions,
'#description' => $this
->t('Separate extensions with a space or comma and do not include the leading dot. Leave empty to allow any extension.'),
'#element_validate' => [
[
FileItem::class,
'validateExtensions',
],
],
'#maxlength' => 256,
];
$element['no_extension'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Allow URLs without file extension'),
'#description' => $this
->t('The link can refer a document such as a wiki page or a dynamic generated page that has no extension. Check this if you want to allow such URLs.'),
'#default_value' => $this
->getSetting('no_extension'),
];
return $element;
}
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$values = parent::generateSampleValue($field_definition);
$values['size'] = 1234567;
$values['format'] = 'image/png';
return $values;
}
public function preSave() {
parent::preSave();
if (Settings::get('file_link.disable_http_requests', FALSE)) {
return;
}
$entity = $this
->getEntity();
$storage = $this
->getEntityTypeManager()
->getStorage($entity
->getEntityTypeId());
$original = $entity
->isNew() ? NULL : $storage
->loadUnchanged($entity
->id());
$field_name = $this
->getFieldDefinition()
->getName();
$original_uri = $original ? $original->{$field_name}->uri : NULL;
$size = $original ? $original->{$field_name}->size : NULL;
$format = $original ? $original->{$field_name}->format : NULL;
$needs_parsing = $entity
->isNew() || $this->uri !== $original_uri || empty($size) || empty($format);
if ($needs_parsing) {
$options = [
'exceptions' => FALSE,
'allow_redirects' => [
'strict' => TRUE,
],
];
$url = Url::fromUri($this->uri, [
'absolute' => TRUE,
])
->toString();
$this
->clearResponse();
$this
->clearException();
try {
$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')) {
$format = explode(';', $response
->getHeaderLine('Content-Type'))[0];
}
else {
$format = NULL;
}
if ($response
->hasHeader('Content-Length')) {
$size = (int) $response
->getHeaderLine('Content-Length');
}
else {
$response = $this
->getHttpClient()
->get($url, $options);
$size = (int) $response
->getBody()
->getSize();
$this
->setResponse($response);
}
$this
->writePropertyValue('size', $size);
$this
->writePropertyValue('format', $format);
}
}
}
public function getSize() {
return $this
->get('size')
->getValue();
}
public function getFormat() {
return $this
->get('format')
->getValue();
}
public function setResponse(ResponseInterface $response) {
$this->response = $response;
return $this;
}
public function getResponse() {
return $this->response;
}
public function clearResponse() {
$this->response = NULL;
return $this;
}
public function setException(RequestException $exception) {
$this->exception = $exception;
return $this;
}
public function getException() {
return $this->exception;
}
public function clearException() {
$this->exception = NULL;
return $this;
}
protected function getEntityTypeManager() {
if (!isset($this->entityTypeManager)) {
$this->entityTypeManager = \Drupal::entityTypeManager();
}
return $this->entityTypeManager;
}
protected function getHttpClient() {
if (!isset($this->httpClient)) {
$this->httpClient = \Drupal::httpClient();
}
return $this->httpClient;
}
protected function isSupportedResponse(ResponseInterface $response) {
return in_array($response
->getStatusCode(), [
'200',
'301',
'302',
]);
}
}