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 }}
```
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
order to get URL of specific item specify its delta explicitly using array
notation.
@ -316,6 +322,12 @@ Media fields are fully supported including OEmbed resources.
{{ 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 filter is disabled by default. You can enable it in settings.php file as
follows:

38
src/TwigTweakExtension.php

@ -605,18 +605,7 @@ class TwigTweakExtension extends AbstractExtension {
* A URL that may be used to access the file.
*/
public static function fileUrlFilter($input): ?string {
if (is_string($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);
}
return \Drupal::service('twig_tweak.url_extractor')->extractUrl($input);
}
/**
@ -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:
class: Drupal\twig_tweak\View\ImageViewBuilder
twig_tweak.url_extractor:
class: Drupal\twig_tweak\UrlExtractor
arguments: ['@entity_type.manager']

Loading…
Cancel
Save