diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php
index b82d5a8..8571cb0 100644
--- a/core/modules/file/src/Entity/File.php
+++ b/core/modules/file/src/Entity/File.php
@@ -4,9 +4,12 @@
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
+use Drupal\Core\Entity\EntityMalformedException;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Url;
use Drupal\file\FileInterface;
use Drupal\user\UserInterface;
@@ -71,7 +74,50 @@ public function setFileUri($uri) {
* @see file_url_transform_relative()
*/
public function url($rel = 'canonical', $options = array()) {
- return file_create_url($this->getFileUri());
+ /** @var Url $uri */
+ $uri = $this->toUrl($rel);
+ $options += $uri->getOptions();
+ $uri->setOptions($options);
+ return $uri->toString();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toUrl($rel = 'canonical', array $options = []) {
+ // Core does not provide any link templates for files so build the canonical
+ // URL manually, but allow contrib to provide link templates.
+ try {
+ return parent::toUrl($rel, $options);
+ } catch (UndefinedLinkTemplateException $e) {
+ return $this->handleCanonicalUrlExceptions($rel, $options, $e);
+ } catch (EntityMalformedException $e) {
+ return $this->handleCanonicalUrlExceptions($rel, $options, $e);
+ }
+ }
+
+ /**
+ * If we want to have a canoncial url, but don't have a linktemplate or a uri_callback,
+ * build an Url from the file uri
+ *
+ * @param string $rel
+ * The link relationship type, for example: canonical or edit-form.
+ * @param array $options
+ * See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for
+ * the available options.
+ * @param UndefinedLinkTemplateException|EntityMalformedException $e
+ * The Exceptions thrown from toUrl
+ * @return \Drupal\Core\Url
+ * @throws UndefinedLinkTemplateException|EntityMalformedException
+ * If we don't want a canonical Url
+ */
+ private function handleCanonicalUrlExceptions($rel, $options, $e) {
+ if ($rel == 'canonical') {
+ return Url::fromUri(file_create_url($this->getFileUri()), $options);
+ }
+ else {
+ throw $e;
+ }
}
/**
diff --git a/core/modules/file/tests/src/Kernel/LinkTest.php b/core/modules/file/tests/src/Kernel/LinkTest.php
new file mode 100644
index 0000000..66a0ddb
--- /dev/null
+++ b/core/modules/file/tests/src/Kernel/LinkTest.php
@@ -0,0 +1,48 @@
+createFile('druplicon.txt', NULL, 'public');
+ $this->assertEquals($file->toLink()
+ ->toString(), "toUrl()->toString()}\">{$file->label()}");
+ // Test the deprecated methods as well.
+ $this->assertEquals($file->link(), "url()}\">{$file->label()}");
+ }
+
+ /**
+ * Tests to_url against an uri_callback
+ */
+ function testUriCallback() {
+ $file = $this->createFile('druplicon.txt', NULL, 'public');
+ $expected = $file->toUrl()->toString() . '_test';
+ $file->getEntityType()->setUriCallback(function ($fileEntity) {
+ return Url::fromUri(file_create_url($fileEntity->getFileUri()) . '_test');
+ });
+ $actual = $file->toUrl()->toString();
+ $this->assertEquals($expected, $actual);
+ }
+
+ /**
+ * Tests that only canonical links are supported.
+ */
+ function testNonCanonicalLink() {
+ $this->setExpectedException(UndefinedLinkTemplateException::class);
+
+ $file = $this->createFile('druplicon.txt', NULL, 'public');
+ $file->toLink('', 'notcanonical');
+ }
+}
\ No newline at end of file