Browse Source

Issue #2924925 by Leon Kessler, Etroid: File url from image and media field

merge-requests/4/head
Chi 6 years ago
parent
commit
6b1ae2d7cc
  1. 11
      composer.json
  2. 76
      src/TwigExtension.php
  3. 78
      tests/src/Functional/TwigTweakTest.php
  4. 30
      tests/twig_tweak_test/config/install/core.entity_view_display.media.image.default.yml
  5. 30
      tests/twig_tweak_test/config/install/core.entity_view_display.media.remote_video.default.yml
  6. 48
      tests/twig_tweak_test/config/install/core.entity_view_display.node.page.default.yml
  7. 43
      tests/twig_tweak_test/config/install/field.field.media.image.field_media_image.yml
  8. 21
      tests/twig_tweak_test/config/install/field.field.media.remote_video.field_media_oembed_video.yml
  9. 24
      tests/twig_tweak_test/config/install/field.field.node.page.body.yml
  10. 38
      tests/twig_tweak_test/config/install/field.field.node.page.field_image.yml
  11. 30
      tests/twig_tweak_test/config/install/field.field.node.page.field_media.yml
  12. 35
      tests/twig_tweak_test/config/install/field.storage.media.field_media_image.yml
  13. 23
      tests/twig_tweak_test/config/install/field.storage.media.field_media_oembed_video.yml
  14. 34
      tests/twig_tweak_test/config/install/field.storage.node.field_image.yml
  15. 20
      tests/twig_tweak_test/config/install/field.storage.node.field_media.yml
  16. 16
      tests/twig_tweak_test/config/install/media.type.image.yml
  17. 20
      tests/twig_tweak_test/config/install/media.type.remote_video.yml
  18. 13
      tests/twig_tweak_test/config/install/node.type.page.yml
  19. 6
      tests/twig_tweak_test/templates/twig-tweak-test.html.twig
  20. 3
      tests/twig_tweak_test/twig_tweak_test.info.yml
  21. 2
      twig_tweak.info.yml

11
composer.json

@ -5,11 +5,14 @@
"keywords": ["Drupal", "Twig"],
"license": "GPL-2.0+",
"homepage": "https://www.drupal.org/project/twig_tweak",
"suggest": {
"symfony/var-dumper": "better dump() function for debugging Twig variables"
},
"support": {
"issues": "https://www.drupal.org/project/issues/twig_tweak",
"source": "http://cgit.drupalcode.org/twig_tweak"
"source": "https://git.drupalcode.org/project/twig_tweak"
},
"require": {
"drupal/core": "^8.7"
},
"suggest": {
"symfony/var-dumper": "better dump() function for debugging Twig variables"
}
}

76
src/TwigExtension.php

@ -7,15 +7,21 @@ use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Block\TitleBlockPluginInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Link;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Markup;
use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Drupal\image\Entity\ImageStyle;
use Drupal\media\MediaInterface;
use Drupal\media\Plugin\media\Source\OEmbedInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/**
@ -69,6 +75,7 @@ class TwigExtension extends \Twig_Extension {
new \Twig_SimpleFilter('view', [$this, 'view']),
new \Twig_SimpleFilter('with', [$this, 'with']),
new \Twig_SimpleFilter('children', [$this, 'children']),
new \Twig_SimpleFilter('file_url', [$this, 'fileUrl']),
];
// PHP filter should be enabled in settings.php file.
if (Settings::get('twig_tweak_enable_php_filter')) {
@ -766,6 +773,75 @@ class TwigExtension extends \Twig_Extension {
}
}
/**
* Returns a URL path to the file.
*
* Examples:
*
* For string arguments it works similar to core file_url() Twig function.
* @code
* {{ 'public://sea.jpg'|file_url }}
* @endcode
*
* 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.
* @code
* {{ node.field_image|file_url }}
* {{ node.field_image[0]|file_url }}
* @endcode
*
* Media fields are fully supported including OEmbed resources.
* @code
* {{ node.field_media|file_url }}
* @endcode
*
* @param string|object $input
* Can be either file URI or an object that contains the URI.
*
* @return string|null
* A URL that may be used to access the file.
*/
public function fileUrl($input) {
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);
}
}
/**
* Extracts file URL form content entity.
*
* @param object $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($entity) {
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();
}
}
/**
* Evaluates a string of PHP code.
*

78
tests/src/Functional/TwigTweakTest.php

@ -6,9 +6,11 @@ use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\media\Entity\Media;
use Drupal\responsive_image\Entity\ResponsiveImageStyle;
use Drupal\Core\Render\Markup;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\TestFileCreationTrait;
use Drupal\user\Entity\Role;
/**
@ -18,6 +20,8 @@ use Drupal\user\Entity\Role;
*/
class TwigTweakTest extends BrowserTestBase {
use TestFileCreationTrait;
/**
* {@inheritdoc}
*/
@ -37,19 +41,45 @@ class TwigTweakTest extends BrowserTestBase {
*/
public function setUp() {
parent::setUp();
$this->createContentType(['type' => 'page']);
$this->createNode(['title' => 'Alpha']);
$this->createNode(['title' => 'Beta']);
$this->createNode(['title' => 'Gamma']);
file_unmanaged_copy(DRUPAL_ROOT . '/core/misc/druplicon.png', 'public://druplicon.png');
$file = File::create([
'uri' => 'public://druplicon.png',
'filename' => 'druplicon.png',
$test_files = $this->getTestFiles('image');
$image_file = File::create([
'uri' => $test_files[0]->uri,
'uuid' => 'b2c22b6f-7bf8-4da4-9de5-316e93487518',
'status' => 1,
'status' => FILE_STATUS_PERMANENT,
]);
$image_file->save();
$media_file = File::create([
'uri' => $test_files[8]->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()],
]);
$file->save();
$media->save();
$node_values = [
'title' => 'Alpha',
'field_image' => [
'target_id' => $image_file->id(),
'alt' => 'Alt text',
'title' => 'Title',
],
'field_media' => [
'target_id' => $media->id(),
],
];
$this->createNode($node_values);
$this->createNode(['title' => 'Beta']);
$this->createNode(['title' => 'Gamma']);
ResponsiveImageStyle::create([
'id' => 'example',
@ -181,23 +211,23 @@ class TwigTweakTest extends BrowserTestBase {
$this->assertByXpath($xpath);
// Test image by FID.
$xpath = '//div[@class = "tt-image-by-fid"]/img[contains(@src, "/files/druplicon.png")]';
$xpath = '//div[@class = "tt-image-by-fid"]/img[contains(@src, "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test image by URI.
$xpath = '//div[@class = "tt-image-by-uri"]/img[contains(@src, "/files/druplicon.png")]';
$xpath = '//div[@class = "tt-image-by-uri"]/img[contains(@src, "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test image by UUID.
$xpath = '//div[@class = "tt-image-by-uuid"]/img[contains(@src, "/files/druplicon.png")]';
$xpath = '//div[@class = "tt-image-by-uuid"]/img[contains(@src, "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test image with style.
$xpath = '//div[@class = "tt-image-with-style"]/img[contains(@src, "/files/styles/thumbnail/public/druplicon.png")]';
$xpath = '//div[@class = "tt-image-with-style"]/img[contains(@src, "/files/styles/thumbnail/public/image-test.png")]';
$this->assertByXpath($xpath);
// Test image with responsive style.
$xpath = '//div[@class = "tt-image-with-responsive-style"]/picture/img[contains(@src, "/files/druplicon.png")]';
$xpath = '//div[@class = "tt-image-with-responsive-style"]/picture/img[contains(@src, "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test token.
@ -285,7 +315,6 @@ class TwigTweakTest extends BrowserTestBase {
// Test node view.
$xpath = '//div[@class = "tt-node-view"]/article[contains(@class, "node--view-mode-default")]/h2[a/span[text() = "Beta"]]';
$xpath .= '/following-sibling::footer[//h4[text() = "Member for"]]';
$xpath .= '/following-sibling::div[@class = "node__content"]/div/p';
$this->assertByXpath($xpath);
@ -296,6 +325,23 @@ class TwigTweakTest extends BrowserTestBase {
// Field item view.
$xpath = '//div[@class = "tt-field-item-view" and text() = "Beta"]';
$this->assertByXpath($xpath);
// Test file URL from URI.
$xpath = '//div[@class = "tt-file-url-from-uri" and contains(text(), "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test file URL from image field.
$this->drupalGet('/node/1');
$xpath = '//div[@class = "tt-file-url-from-image-field" and contains(text(), "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test file URL from a specific image field item.
$xpath = '//div[@class = "tt-file-url-from-image-field-delta" and contains(text(), "/files/image-test.png")]';
$this->assertByXpath($xpath);
// Test file URL from media field.
$xpath = '//div[@class = "tt-file-url-from-media-field" and contains(text(), "/files/image-1.png")]';
$this->assertByXpath($xpath);
}
/**

30
tests/twig_tweak_test/config/install/core.entity_view_display.media.image.default.yml

@ -0,0 +1,30 @@
uuid: 42d67a69-5099-4c17-b27e-32080699966b
langcode: en
status: true
dependencies:
config:
- field.field.media.image.field_media_image
- media.type.image
module:
- image
_core:
default_config_hash: jOwnt_yq6AKAfqU6f0xKnxEkFQ2eTPJWxrk3WMLbL68
id: media.image.default
targetEntityType: media
bundle: image
mode: default
content:
field_media_image:
label: visually_hidden
settings:
image_style: ''
image_link: file
third_party_settings: { }
type: image
weight: 1
region: content
hidden:
created: true
name: true
thumbnail: true
uid: true

30
tests/twig_tweak_test/config/install/core.entity_view_display.media.remote_video.default.yml

@ -0,0 +1,30 @@
uuid: af776ed7-7db5-4670-b70b-4c94e06a6867
langcode: en
status: true
dependencies:
config:
- field.field.media.remote_video.field_media_oembed_video
- media.type.remote_video
module:
- media
_core:
default_config_hash: gUaDZKMQD3lmLKWPn727X3JHVdKJ525g4EJCCcDVAqk
id: media.remote_video.default
targetEntityType: media
bundle: remote_video
mode: default
content:
field_media_oembed_video:
type: oembed
weight: 0
label: hidden
settings:
max_width: 0
max_height: 0
third_party_settings: { }
region: content
hidden:
created: true
name: true
thumbnail: true
uid: true

48
tests/twig_tweak_test/config/install/core.entity_view_display.node.page.default.yml

@ -0,0 +1,48 @@
uuid: 3fd16a0f-7a0d-46aa-8b80-2b1dc8484d09
langcode: en
status: true
dependencies:
config:
- field.field.node.page.body
- field.field.node.page.field_image
- field.field.node.page.field_media
- node.type.page
module:
- image
- text
- user
_core:
default_config_hash: g1S3_GLaxq4l3I9RIca5Mlz02MxI2KmOquZpHw59akM
id: node.page.default
targetEntityType: node
bundle: page
mode: default
content:
body:
label: hidden
type: text_default
weight: 100
region: content
settings: { }
third_party_settings: { }
field_image:
weight: 102
label: above
settings:
image_style: ''
image_link: ''
third_party_settings: { }
type: image
region: content
field_media:
weight: 103
label: above
settings:
link: true
third_party_settings: { }
type: entity_reference_label
region: content
links:
weight: 101
region: content
hidden: { }

43
tests/twig_tweak_test/config/install/field.field.media.image.field_media_image.yml

@ -0,0 +1,43 @@
uuid: 31cfb877-de82-4020-b0f7-9ec72592495f
langcode: en
status: true
dependencies:
config:
- field.storage.media.field_media_image
- media.type.image
enforced:
module:
- media
module:
- image
_core:
default_config_hash: pzPA-2JwyxlJ3qMb4L9viAnhNhbEhl2couH8A3FO020
id: media.image.field_media_image
field_name: field_media_image
entity_type: media
bundle: image
label: Image
description: ''
required: true
translatable: true
default_value: { }
default_value_callback: ''
settings:
alt_field: true
alt_field_required: true
title_field: false
title_field_required: false
max_resolution: ''
min_resolution: ''
default_image:
uuid: null
alt: ''
title: ''
width: null
height: null
file_directory: '[date:custom:Y]-[date:custom:m]'
file_extensions: 'png gif jpg jpeg'
max_filesize: ''
handler: 'default:file'
handler_settings: { }
field_type: image

21
tests/twig_tweak_test/config/install/field.field.media.remote_video.field_media_oembed_video.yml

@ -0,0 +1,21 @@
uuid: 83889a69-28e6-470c-bf31-4437a5a2c1cf
langcode: en
status: true
dependencies:
config:
- field.storage.media.field_media_oembed_video
- media.type.remote_video
_core:
default_config_hash: Eo4HHenV5iZat_kEWgr_wydD3TgwURMCzwt-7qIEyoM
id: media.remote_video.field_media_oembed_video
field_name: field_media_oembed_video
entity_type: media
bundle: remote_video
label: 'Video URL'
description: ''
required: true
translatable: true
default_value: { }
default_value_callback: ''
settings: { }
field_type: string

24
tests/twig_tweak_test/config/install/field.field.node.page.body.yml

@ -0,0 +1,24 @@
uuid: 42500952-ebb3-46c2-9a86-ed2f6c4000c1
langcode: en
status: true
dependencies:
config:
- field.storage.node.body
- node.type.page
module:
- text
_core:
default_config_hash: rUop-8b6hvxxDYbv-KobTfNIBNbPY9qOPl8f6kBNSpw
id: node.page.body
field_name: body
entity_type: node
bundle: page
label: Body
description: ''
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
display_summary: true
field_type: text_with_summary

38
tests/twig_tweak_test/config/install/field.field.node.page.field_image.yml

@ -0,0 +1,38 @@
uuid: 0f21b708-4832-4777-91ea-236dddea0236
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_image
- node.type.page
module:
- image
id: node.page.field_image
field_name: field_image
entity_type: node
bundle: page
label: Image
description: ''
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
file_directory: '[date:custom:Y]-[date:custom:m]'
file_extensions: 'png gif jpg jpeg'
max_filesize: ''
max_resolution: ''
min_resolution: ''
alt_field: true
alt_field_required: true
title_field: false
title_field_required: false
default_image:
uuid: ''
alt: ''
title: ''
width: null
height: null
handler: 'default:file'
handler_settings: { }
field_type: image

30
tests/twig_tweak_test/config/install/field.field.node.page.field_media.yml

@ -0,0 +1,30 @@
uuid: cc6b99d7-25b6-4d90-a65e-4021861ec6af
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_media
- media.type.image
- media.type.remote_video
- node.type.page
id: node.page.field_media
field_name: field_media
entity_type: node
bundle: page
label: Media
description: ''
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
handler: 'default:media'
handler_settings:
target_bundles:
image: image
remote_video: remote_video
sort:
field: _none
auto_create: false
auto_create_bundle: image
field_type: entity_reference

35
tests/twig_tweak_test/config/install/field.storage.media.field_media_image.yml

@ -0,0 +1,35 @@
uuid: e8eb0ecd-b286-4d09-9152-fcc1e7868f17
langcode: en
status: true
dependencies:
enforced:
module:
- media
module:
- file
- image
- media
_core:
default_config_hash: 7ZBrcl87ZXaw42v952wwcw_9cQgTBq5_5tgyUkE-VV0
id: media.field_media_image
field_name: field_media_image
entity_type: media
type: image
settings:
default_image:
uuid: null
alt: ''
title: ''
width: null
height: null
target_type: file
display_field: false
display_default: false
uri_scheme: public
module: image
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false

23
tests/twig_tweak_test/config/install/field.storage.media.field_media_oembed_video.yml

@ -0,0 +1,23 @@
uuid: d879f1f4-2730-47bb-9f38-df6c265855b9
langcode: en
status: true
dependencies:
module:
- media
_core:
default_config_hash: SJgxR5XWOesQbEKqp8VgInPyJjCFU_t2pi7UzYB78xg
id: media.field_media_oembed_video
field_name: field_media_oembed_video
entity_type: media
type: string
settings:
max_length: 255
is_ascii: false
case_sensitive: false
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false

34
tests/twig_tweak_test/config/install/field.storage.node.field_image.yml

@ -0,0 +1,34 @@
uuid: 7d45d63c-3a03-4a65-8103-b12e70c69948
langcode: en
status: true
dependencies:
module:
- file
- image
- node
_core:
default_config_hash: SkXIPKZYiIMMtnBmfnxk58RYfbZ8cHSw5NZPY_JByME
id: node.field_image
field_name: field_image
entity_type: node
type: image
settings:
uri_scheme: public
default_image:
uuid: null
alt: ''
title: ''
width: null
height: null
target_type: file
display_field: false
display_default: false
module: image
locked: false
cardinality: 1
translatable: true
indexes:
target_id:
- target_id
persist_with_no_fields: false
custom_storage: false

20
tests/twig_tweak_test/config/install/field.storage.node.field_media.yml

@ -0,0 +1,20 @@
uuid: 8301cf4c-fba5-440b-8323-9a0019c12d34
langcode: en
status: true
dependencies:
module:
- media
- node
id: node.field_media
field_name: field_media
entity_type: node
type: entity_reference
settings:
target_type: media
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false

16
tests/twig_tweak_test/config/install/media.type.image.yml

@ -0,0 +1,16 @@
uuid: 6ef5b8e7-988c-4057-8a44-55fa195fef14
langcode: en
status: true
dependencies: { }
_core:
default_config_hash: 6Qope5wG7HUpV0tPOBMtDI_GZkHFcF1Xj4hgD9Cu_hM
id: image
label: Image
description: 'Use local images for reusable media.'
source: image
queue_thumbnail_downloads: false
new_revision: true
source_configuration:
source_field: field_media_image
field_map:
name: name

20
tests/twig_tweak_test/config/install/media.type.remote_video.yml

@ -0,0 +1,20 @@
uuid: 1b4d7544-7b5e-47d2-b79e-d50d6b2442a0
langcode: en
status: true
dependencies: { }
_core:
default_config_hash: d_nPD2eMknkYAnSTV4FkaqijceyFJPwT5i_Ih0lEEtc
id: remote_video
label: 'Remote video'
description: 'A remotely hosted video from YouTube or Vimeo.'
source: 'oembed:video'
queue_thumbnail_downloads: false
new_revision: false
source_configuration:
thumbnails_directory: 'public://oembed_thumbnails'
providers:
- YouTube
- Vimeo
source_field: field_media_oembed_video
field_map:
title: name

13
tests/twig_tweak_test/config/install/node.type.page.yml

@ -0,0 +1,13 @@
uuid: 963c690a-b7c3-48dd-bc35-351857b9a7ce
langcode: en
status: true
dependencies: { }
_core:
default_config_hash: KuyA4NHPXcmKAjRtwa0vQc2ZcyrUJy6IlS2TAyMNRbc
name: 'Basic page'
type: page
description: 'Use <em>basic pages</em> for your static content, such as an ''About us'' page.'
help: ''
new_revision: true
preview_mode: 1
display_submitted: false

6
tests/twig_tweak_test/templates/twig-tweak-test.html.twig

@ -35,7 +35,7 @@
<div class="tt-menu-depth">{{ drupal_menu('twig-tweak-test', 1, 1) }}</div>
<div class="tt-form">{{ drupal_form('Drupal\\system\\Form\\CronForm') }}</div>
<div class="tt-image-by-fid">{{ drupal_image(1, attributes=image_attributes) }}</div>
<div class="tt-image-by-uri">{{ drupal_image('public://druplicon.png', attributes=image_attributes) }}</div>
<div class="tt-image-by-uri">{{ drupal_image('public://image-test.png', attributes=image_attributes) }}</div>
<div class="tt-image-by-uuid">{{ drupal_image('b2c22b6f-7bf8-4da4-9de5-316e93487518', attributes=image_attributes) }}</div>
<div class="tt-image-with-style">{{ drupal_image(1, 'thumbnail', image_attributes) }}</div>
<div class="tt-image-with-responsive-style">{{ drupal_image(1, 'example', image_attributes, true) }}</div>
@ -76,4 +76,8 @@
<div class="tt-node-view">{{ node|view }}</div>
<div class="tt-field-list-view">{{ node.title|view }}</div>
<div class="tt-field-item-view">{{ node.title[0]|view }}</div>
<div class="tt-file-url-from-uri">{{ 'public://image-test.png'|file_url }}</div>
<div class="tt-file-url-from-image-field">{{ node.field_image|file_url }}</div>
<div class="tt-file-url-from-image-field-delta">{{ node.field_image[0]|file_url }}</div>
<div class="tt-file-url-from-media-field">{{ node.field_media|file_url }}</div>
</div>

3
tests/twig_tweak_test/twig_tweak_test.info.yml

@ -4,6 +4,7 @@ description: Support module for Twig tweak testing.
package: Testing
core: 8.x
dependencies:
- drupal:system (>= 8.5.0)
- drupal:system (>= 8.7.0)
- drupal:node
- drupal:media
- drupal:twig_tweak

2
twig_tweak.info.yml

@ -2,3 +2,5 @@ name: Twig Tweak
type: module
description: Provides some extra Twig functions and filters.
core: 8.x
dependencies:
- drupal:system (>=8.7)

Loading…
Cancel
Save