Browse Source

Add URL extractor service

merge-requests/2/head
Chi 4 years ago
parent
commit
826cbd5e4c
  1. 12
      README.md
  2. 38
      src/TwigTweakExtension.php
  3. 96
      src/UrlExtractor.php
  4. 168
      tests/src/Kernel/UrlExtractorTest.php
  5. 4
      twig_tweak.services.yml

12
README.md

@ -303,6 +303,12 @@ For string arguments it works similar to core `file_url()` Twig function.
{{ 'public://sea.jpg'|file_url }} {{ 'public://sea.jpg'|file_url }}
``` ```
In order to generate absolute URL set "relative" parameter to `false`.
```twig
{{ 'public://sea.jpg'|file_url(relative=false) }}
{{ 'public://sea.jpg'|file_url(false) }}
```
When field item list passed the URL will be extracted from the first item. In When field item list passed the URL will be extracted from the first item. In
order to get URL of specific item specify its delta explicitly using array order to get URL of specific item specify its delta explicitly using array
notation. notation.
@ -316,6 +322,12 @@ Media fields are fully supported including OEmbed resources.
{{ node.field_media|file_url }} {{ node.field_media|file_url }}
``` ```
It is also possible to extract file URL directly from an entity.
```twig
{{ image|file_url }}
{{ media|file_url }}
```
### PHP ### PHP
PHP filter is disabled by default. You can enable it in settings.php file as PHP filter is disabled by default. You can enable it in settings.php file as
follows: follows:

38
src/TwigTweakExtension.php

@ -605,18 +605,7 @@ class TwigTweakExtension extends AbstractExtension {
* A URL that may be used to access the file. * A URL that may be used to access the file.
*/ */
public static function fileUrlFilter($input): ?string { public static function fileUrlFilter($input): ?string {
if (is_string($input)) { return \Drupal::service('twig_tweak.url_extractor')->extractUrl($input);
return file_url_transform_relative(file_create_url($input));
}
if ($input instanceof EntityReferenceFieldItemListInterface) {
$referenced_entities = $input->referencedEntities();
if (isset($referenced_entities[0])) {
return self::getUrlFromEntity($referenced_entities[0]);
}
}
elseif ($input instanceof EntityReferenceItem) {
return self::getUrlFromEntity($input->entity);
}
} }
/** /**
@ -666,29 +655,4 @@ class TwigTweakExtension extends AbstractExtension {
} }
} }
/**
* Extracts file URL from content entity.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* Entity object that contains information about the file.
*
* @return string|null
* A URL that may be used to access the file.
*/
private static function getUrlFromEntity(EntityInterface $entity): ?string {
if ($entity instanceof MediaInterface) {
$source = $entity->getSource();
$value = $source->getSourceFieldValue($entity);
if ($source instanceof OEmbedInterface) {
return $value;
}
elseif ($file = File::load($value)) {
return $file->createFileUrl();
}
}
elseif ($entity instanceof FileInterface) {
return $entity->createFileUrl();
}
}
} }

96
src/UrlExtractor.php

@ -0,0 +1,96 @@
<?php
namespace Drupal\twig_tweak;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\file\FileInterface;
use Drupal\media\MediaInterface;
use Drupal\media\Plugin\media\Source\OEmbedInterface;
/**
* UrlExtractor service.
*/
class UrlExtractor {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a UrlExtractor object.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* Extracts file URL from a string or object.
*
* @param string|object $input
* Can be either file URI or an object that contains the URI.
* @param bool $relative
* (optional) Whether the URL should be root-relative, defaults to TRUE.
*
* @return string|null
* A URL that may be used to access the file.
*/
public function extractUrl($input, bool $relative = TRUE): ?string {
if (is_string($input)) {
$url = file_create_url($input);
return $relative ? file_url_transform_relative($url) : $url;
}
elseif ($input instanceof ContentEntityInterface) {
return $this->getUrlFromEntity($input, $relative);
}
elseif ($input instanceof EntityReferenceFieldItemListInterface) {
if ($item = $input->first()) {
return $this->getUrlFromEntity($item->entity, $relative);
}
}
elseif ($input instanceof EntityReferenceItem) {
return $this->getUrlFromEntity($input->entity, $relative);
}
return NULL;
}
/**
* Extracts file URL from content entity.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* Entity object that contains information about the file.
* @param bool $relative
* (optional) Whether the URL should be root-relative, defaults to TRUE.
*
* @return string|null
* A URL that may be used to access the file.
*/
private function getUrlFromEntity(ContentEntityInterface $entity, bool $relative = TRUE): ?string {
if ($entity instanceof MediaInterface) {
$source = $entity->getSource();
$value = $source->getSourceFieldValue($entity);
if (!$value) {
return NULL;
}
elseif ($source instanceof OEmbedInterface) {
return $value;
}
else {
$file = $this->entityTypeManager->getStorage('file')->load($value);
if ($file) {
return $file->createFileUrl($relative);
}
}
}
elseif ($entity instanceof FileInterface) {
return $entity->createFileUrl($relative);
}
return NULL;
}
}

168
tests/src/Kernel/UrlExtractorTest.php

@ -0,0 +1,168 @@
<?php
namespace Drupal\Tests\twig_tweak\Kernel;
use Drupal\file\Entity\File;
use Drupal\KernelTests\KernelTestBase;
use Drupal\media\Entity\Media;
use Drupal\node\Entity\Node;
use Drupal\Tests\TestFileCreationTrait;
/**
* A test for UrlExtractor.
*
* @group twig_tweak
*/
final class UrlExtractorTest extends KernelTestBase {
use TestFileCreationTrait;
/**
* A node to test.
*
* @var \Drupal\node\NodeInterface
*/
private $node;
/**
* {@inheritdoc}
*/
public static $modules = [
'twig_tweak',
'twig_tweak_test',
'system',
'views',
'node',
'block',
'image',
'field',
'text',
'media',
'file',
'user',
'filter',
];
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->installConfig(['node', 'twig_tweak_test']);
$this->installSchema('file', 'file_usage');
$this->installEntitySchema('file');
$this->installEntitySchema('media');
$test_files = $this->getTestFiles('image');
//
$image_file = File::create([
'uri' => $test_files[0]->uri,
'uuid' => 'a2cb2b6f-7bf8-4da4-9de5-316e93487518',
'status' => FILE_STATUS_PERMANENT,
]);
$image_file->save();
$media_file = File::create([
'uri' => $test_files[2]->uri,
'uuid' => '5dd794d0-cb75-4130-9296-838aebc1fe74',
'status' => FILE_STATUS_PERMANENT,
]);
$media_file->save();
$media = Media::create([
'bundle' => 'image',
'name' => 'Image 1',
'field_media_image' => ['target_id' => $media_file->id()],
]);
$media->save();
$node_values = [
'title' => 'Alpha',
'type' => 'page',
'field_image' => [
'target_id' => $image_file->id(),
],
'field_media' => [
'target_id' => $media->id(),
],
];
$this->node = Node::create($node_values);
}
/**
* Test callback.
*/
public function testUrlExtractor(): void {
$extractor = $this->container->get('twig_tweak.url_extractor');
$base_url = file_create_url('');
$request = \Drupal::request();
$absolute_url = "{$request->getScheme()}://{$request->getHost()}/foo/bar.txt";
$url = $extractor->extractUrl($absolute_url);
self::assertSame('/foo/bar.txt', $url);
$url = $extractor->extractUrl($absolute_url, FALSE);
self::assertSame($base_url . 'foo/bar.txt', $url);
$url = $extractor->extractUrl('foo/bar.jpg');
self::assertSame('/foo/bar.jpg', $url);
$url = $extractor->extractUrl('foo/bar.jpg', FALSE);
self::assertSame($base_url . 'foo/bar.jpg', $url);
$url = $extractor->extractUrl('');
self::assertSame('/', $url);
$url = $extractor->extractUrl('', FALSE);
self::assertSame($base_url, $url);
$url = $extractor->extractUrl(NULL);
self::assertNull($url);
$url = $extractor->extractUrl($this->node);
self::assertNull($url);
$url = $extractor->extractUrl($this->node->get('title'));
self::assertNull($url);
$url = $extractor->extractUrl($this->node->get('field_image')[0]);
self::assertStringEndsWith('/files/image-test.png', $url);
self::assertStringNotContainsString($base_url, $url);
$url = $extractor->extractUrl($this->node->get('field_image')[0], FALSE);
self::assertStringStartsWith($base_url, $url);
self::assertStringEndsWith('/files/image-test.png', $url);
$url = $extractor->extractUrl($this->node->get('field_image')[1]);
self::assertNull($url);
$url = $extractor->extractUrl($this->node->get('field_image'));
self::assertStringEndsWith('/files/image-test.png', $url);
$url = $extractor->extractUrl($this->node->get('field_image')->entity);
self::assertStringEndsWith('/files/image-test.png', $url);
$this->node->get('field_image')->removeItem(0);
$url = $extractor->extractUrl($this->node->get('field_image'));
self::assertNull($url);
$url = $extractor->extractUrl($this->node->get('field_media')[0]);
self::assertStringEndsWith('/files/image-test.gif', $url);
$url = $extractor->extractUrl($this->node->get('field_media')[1]);
self::assertNull($url);
$url = $extractor->extractUrl($this->node->get('field_media'));
self::assertStringEndsWith('/files/image-test.gif', $url);
$url = $extractor->extractUrl($this->node->get('field_media')->entity);
self::assertStringEndsWith('/files/image-test.gif', $url);
$this->node->get('field_media')->removeItem(0);
$url = $extractor->extractUrl($this->node->get('field_media'));
self::assertNull($url);
}
}

4
twig_tweak.services.yml

@ -31,3 +31,7 @@ services:
twig_tweak.image_view_builder: twig_tweak.image_view_builder:
class: Drupal\twig_tweak\View\ImageViewBuilder class: Drupal\twig_tweak\View\ImageViewBuilder
twig_tweak.url_extractor:
class: Drupal\twig_tweak\UrlExtractor
arguments: ['@entity_type.manager']

Loading…
Cancel
Save