6

How can a Url object be created from a file URI? Using the URI for a public file as a parameter for Url::fromUri() gives this error.

UnexpectedValueException: External URLs do not have internal route parameters. in Drupal\Core\Url->getRouteParameters().

$file = File::load($file_id);
$file_uri = $file->getFileUri();
$menu_link['url'] = Url::fromUri($file_uri);

Here is the class and method in question: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Url.php/function/Url%3A%3AfromUri/8.2.x

Note that I don't need to get the actual URL in string format, I need to generate a Url object from the Url class that points to a file. This is because I am attempting to modify the path of a menu link and unfortunately that is not a simple matter of providing a URL string in Drupal 8.

This is the code I am using.

function teeprop_preprocess_menu__main(&$vars) {
  foreach($vars['items'] as $key => $menu_link) {
    if (!empty($menu_link['url']->getRouteParameters())) {
      $node_id = $menu_link['url']->getRouteParameters()['node'];
      $node_entity = Node::load($node_id);
      $node_type = $node_entity->getType();

      if ($node_type == 'pdf') {
        $file_id = $node_entity->get('field_pdf_file')->getValue()[0]['target_id'];
        $file = File::load($file_id);
//         $file_url = $file->url();
        $file_uri = $file->getFileUri();
        $vars['items'][$key]['url'] = Url::fromUri($file_uri, ['absolute' => TRUE]);
      }
    }
  }
}
8
  • I'm not sure if this will work for menu link URLs, but I think that external URLs are supported. This could be done by doing $menu_link['url'] = Url::fromUri($file_uri, ['absolute' => TRUE]);. I'm not confident in this, but I use this in freelinking module to send file URIs to Link render element's #uri property.
    – mradcliffe
    Commented Sep 26, 2017 at 22:06
  • Thank you for the suggestion. Unfortunately that causes the same error. I can't believe how difficult this is. Commented Sep 26, 2017 at 22:28
  • file_create_url($file->getFileUri() should create an absolute path which should then work with fromUri().
    – Berdir
    Commented Sep 26, 2017 at 23:11
  • That also fails with the same error. I wonder why is the Url being interpreted as external? Commented Sep 27, 2017 at 4:14
  • Can you POST file URI here..
    – Ajay Reddy
    Commented Sep 27, 2017 at 6:21

3 Answers 3

2

I believe that the following should do what you need:

Url::fromUri(
  File::load(1)->url()
);

(I've tested this in a local 8.4.2 installation, and it yields a Url object that can be rendered without an error.)

The functions are admittedly named very misleadingly. Even though ::fromUri() sounds like it should accept the return value of ::getFileUri(), namely public://..., it actually only accepts internal:, base:, entity: and "external" URLs.

So you need to use ->url() to get the external URL of the file, and then pass that to ::fromUri().

3
  • 1
    Be careful if you use ->isExternal(), it will consider your internal file as external file. Commented May 15, 2019 at 14:05
  • 1
    @ChristopheCARON yes, this is another example of the terminology being ambiguous/misleading. "External" seemingly refers to all URLs that aren't either Drupal routes or Drupal system files - the public filesystem is considered "external". Commented May 16, 2019 at 9:23
  • $file->url() was deprecated in D9 and removed from D10. See other answers for a working option.
    – Dalin
    Commented Jan 2 at 23:02
1
$url = \Drupal::service('file_url_generator')->generate($file_uri);
$form['elements']['my_link'] = Drupal\Core\Link::fromTextAndUrl('Your_link_title', $url)->toRenderable();

You can also use other methods from Drupal\Core\File like generateAbsoluteString,

0

In Drupal 10

$file = File::load($file_id);
$vars['items'][$key]['url'] = $file->createFileUrl();

That will give you the relative URL as a string. Something like "/sites/default/files/my_file.pdf". If you want an absolute URL for some reason you can use $file->createFileUrl(FALSE).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.