В этой статье я расскажу о некоторых основных вещах, о которых вы должны знать при использовании путей и URL адресов в Drupal, а затем рассмотрю примеры использования каждого из них.
Основные объекты, которые я буду здесь рассматривать, это \Symfony\Component\HttpFoundation\Request, \Drupal\Core\Url и \Drupal\Core\Link, каждый из которых имеет свое собственное применение. Далее я рассмотрю другие способы создания ссылок и URL адресов.
Объект запроса
Когда вы отвечаете на запрос страницы в Drupal, у вас будет доступ к объекту Request. Это экземпляр \Symfony\Component\HttpFoundation\Request, и его можно использовать, чтобы сообщить вам все о текущем запросе. Как видно из названия, на самом деле это компонент Symfony, и поэтому он ничего не знает о Drupal.
Этот объект является важной отправной точкой при поиске информации об URL, поскольку это хороший способ получить текущий путь, хост или другие параметры, отправляемые на страницу.
Получение объекта Request — это случай, когда вы просто запрашиваете его у Drupal. Вы можете сделать это статически, как показано ниже.
$request = \Drupal::request();
Вы также можете использовать внедрение зависимостей, чтобы внедрить сервис request_stack в любой сервис, который вы используете, и вызвать метод getCurrentRequest() в этом сервисе. Это даст вам доступ к тому же объекту.
/** @var \Symfony\Component\HttpFoundation\Request $request */ $request = \Drupal::service('request_stack')->getCurrentRequest();
Получив доступ к этому объекту, вы можете использовать его для проверки текущей ситуации на странице.
Чтобы получить текущее доменное имя сайта, вы можете использовать несколько методов. Метод getHost() просто вернет доменное имя.
$host = $request->getHost();
// www.example.ru
Метод getHttpHost() вызывает метод getHost(), а затем добавляет номер используемого порта, если сайт обслуживается через порт, отличный от 80 (для http) и 443 (для https). Например, используя это на сайте, обслуживаемом через порт 8080.
$host = $request->getHttpHost();
// www.example.ru:8080
Чтобы получить текущую схему сайта, которая будет либо http, либо https, вы можете использовать метод getScheme().
$request->getScheme();
// https
Чтобы получить схему и адрес домена вместе, вы можете использовать getSchemeAndHttpHost(), который объединит вышеуказанные методы в один метод.
$fullUrl = $request->getSchemeAndHttpHost();
// https://www.example.ru
Если вы хотите получить путь к текущей странице, вы можете использовать метод getRequestUri(). Это, очевидно, будет зависеть от страницы, которую вы посещаете, но если предположить, что посещаемая страница — https://www.example.ru/some/internal/page, то возвращаемый путь будет /some/internal/page.
$requestUri = $request->getRequestUri();
// /some/internal/page
Если метод getRequestUri() вызывается с главной страницы сайта, он возвращает «/». Возвращаемый здесь путь также будет содержать любую информацию о языке, что довольно часто встречается на сайтах Drupal.
Наконец, если вы хотите найти параметры запроса, отправляемые на страницу, объект запроса содержит свойство «query», которое содержит эту информацию. Это экземпляр класса \Drupal\Core\Http\InputBag и, по сути, представляет собой набор параметров, отправляемых в запрос.
Например, чтобы получить все параметры запроса в виде массива, вы можете вызвать метод all() для свойства запроса.
$queryParameters = $request->query->all();
// ["parameter1" => "123"]
Объект запроса можно использовать для получения всевозможной информации о запросе. Такие вещи, как файлы cookie, файлы, свойства сервера PHP или любые заголовки, которые отправляются с запросом, доступны аналогично свойству запроса. Для определения текущего домена и пути в классе больше ничего нет.
Объект URL
Прежде чем идти дальше, рекомендуется рассмотреть использование внутреннего класса \Drupal\Core\Url. Это мощный класс, который используется в довольно многих местах в Drupal, поэтому стоит потратить некоторое время, чтобы изучить его.
Этот класс не внедряется ни в какие службы внутри Drupal, но может быть создан с помощью ряда методов или непосредственно инстанцирован. Если вы хотите использовать этот класс, вам просто нужно добавить пространство имен в начало файла и начать использовать его в своем коде.
use \Drupal\Core\Url;
Чтобы создать экземпляр объекта Url непосредственно через composer, вам нужен маршрут. Маршруты определяются в Drupal в файлах *.routing.yml и, по сути, являются соединениями между путем и классом, который отвечает на этот путь. Есть еще несколько деталей о маршрутах, но это, по сути, все.
Например, маршрут «user.logout» определяет путь «/user/logout», и это указывает на метод \Drupal\user\Controller\UserController::logout. Это означает, что если пользователь посещает путь «/user/logout», на этом контроллере будет вызываться метод logout().
Чтобы создать объект Url с этим маршрутом, мы должны сделать что-то вроде этого.
$url = new Url('user.logout');
Есть также несколько специальных маршрутов, которые используются внутри для определения особых экземпляров.
- <front> — это прямой путь к домашней странице, который на большинстве сайтов Drupal представляет собой косую черту. Если ваш сайт Drupal находится в подкаталоге, то главной страницей будет этот подкаталог.
- <none> — аналогично <front>, за исключением того, что он всегда указывает на корень домена.
- <current> — это текущий путь запроса, аналогичный запросу объекта Request для текущего пути.
- <nolink> — используется, когда пользователь должен ввести ссылку, но хочет, чтобы отображался только текст ссылки, без фактического создания ссылки. Это полезно для создания пунктов меню в интерфейсе меню Drupal без указания полной ссылки.
- <button> — это похоже на маршрут <nolink>, но текст ссылки будет отображаться более доступным способом.
Вот пример создания объекта Url для текущего пути запроса.
$url = new \Drupal\Core\Url('<current>');
В качестве альтернативы можно использовать ряд различных методов создания статических объектов в классе Url. Например, мы могли бы написать это так.
$url = Url::fromRoute('<current>');
Это по-прежнему создает объект Url, но в этом методе происходит немного больше подробностей.
Вы также можете использовать метод fromRoute() с именем маршрута, передав имя маршрута методу.
$url = Url::fromRoute('user.logout');
На самом деле существует ряд статических методов создания, которые вы можете использовать в классе Url. Давайте посмотрим на несколько.
Если у вас есть объект Request, вы можете преобразовать его в объект Url с помощью метода createFromRequest().
$url = Url::createFromRequest($request);
Если у вас есть полный URL адрес, возможно, из внешнего ресурса, вы можете использовать метод fromUri().
$url = Url::fromUri('https://www.example.ru/');
Вы также можете передать здесь несколько разных строк в начале параметра, чтобы использовать разные маршруты или пути. Это полезно, если у вас есть внутренний путь, маршрут или сущность.
Чтобы создать URL адрес действительного внутреннего пути, используйте префикс «internal:».
$url = Url::fromUri('internal:/user/logout');
Чтобы создать ссылку на действительный внутренний маршрут, используйте префикс «route:».
$url = Url::fromUri('route:user.logout');
Примечание
Будьте осторожны, так как объект Url будет создан, даже если внутренний путь или маршрут недействительны. Вы поймете, что эта проблема, только когда начнете использовать этот объект Url, поскольку Drupal выдаст ошибку.
Если вы хотите создать ссылку на путь, который не существует на вашем сайте, вы можете использовать префикс «base:».
$url = Url::fromUri('base:/some/random/path');
Это позволит вам использовать объект Url без выдачи ошибки из-за того, что путь не существует.
Если вы принимаете пользовательский ввод, рекомендуется использовать метод fromUserInput() для создания URL адреса. Это позволит вам создать объект Url, не создавая проблем из-за отсутствующих маршрутов или неверных путей.
$url = Url::fromUserInput('/some/path');
Наконец, есть метод fromRouteMatch(), который требует передачи объекта \Drupal\Core\Routing\RouteMatch в качестве параметра. Это особый тип объекта, который представляет маршрут, а не загружает сам маршрут.
Конструктор принимает параметр параметров маршрута, который можно передать создаваемому URL адресу. Это означает, что при использовании маршрута, принимающего параметры, параметры могут быть добавлены в конструктор в виде массива. Вот пример создания URL адреса узла.
$request = \Drupal::request();
$route_match = RouteMatch::createFromRequest($request);
$url = \Drupal\Core\Url::fromRouteMatch($route_match);
Сгенерированный здесь объект Url будет действовать так же, как объект, созданный с помощью маршрута.
Добавление параметров
Кроме того, большинству этих функций можно передать дополнительные параметры, чтобы изменить способ создания объекта Url.
Конструктор принимает параметр параметров маршрута, который можно передать создаваемому URL адресу. Это означает, что при использовании маршрута, принимающего параметры, параметры могут быть добавлены в конструктор в виде массива. Вот пример создания URL адреса узла.
$url = new Url('entity.node.canonical', ['node' => 1]);
Также возможно изменить некоторые аспекты создаваемого URL. Например, чтобы добавить некоторые параметры запроса к URL адресу, вы можете передать такой массив.
$url = new Url('entity.node.canonical', ['node' => 1], ['query' => ['parameter' => '123']]);
Большинство статических методов в классе принимают параметр options. Метод fromRoute() является единственным методом, который также принимает параметры параметров маршрута так же, как и конструктор.
$url = Url::fromRoute('entity.node.canonical', ['node' => 1], ['query' => ['parameter' => '123']);
Аналогичным образом можно использовать метод fromUri().
$url = Url::fromUri('internal:/user/logout', ['query' => ['parameter' => '123']]);
Использование объекта URL
Теперь, когда мы создали объект Url, мы должны посмотреть, для чего он используется. Сам объект Url можно использовать для изменения различных аспектов пути или маршрута и отображения URL адреса в виде строки.
Можно использовать три метода для преобразования URL адреса в пригодное для вывода состояние.
Самый простой вариант — вывести URL адрес в виде строки.
$url = Url::fromUri('route:user.logout');
$string = $url->toString();
// /user/logout
Если вы выводите маршрут к объекту, то класс Url преобразует его в полный псевдоним пути объекта.
$url = Url::fromRoute('entity.node.canonical', ['node' => 1]);
$string = $url->toString();
// /full/path/to/the/node
Вы также можете отобразить URL адрес как маршрут Drupal, используя метод toUriString(), который также будет включать любую информацию о параметрах маршрута, установленных в объекте Url. Это полезно при сохранении URL адреса в таблице базы данных, поскольку это представление URL адреса, которое можно преобразовать обратно в пригодный для использования объект URL адреса.
$url = Url::fromUri('route:user.logout');
$uriString = $url->toUriString();
// route:user.logout
Также можно сгенерировать массив рендеринга с помощью метода toRenderArray(). Это может быть полезно, если URL адрес необходимо вывести пользователю из блока или контроллера.
$url = Url::fromUri('route:user.logout');
$renderArray = $url->toRenderArray();
Если у вас есть объект Url, вы можете запустить несколько методов, чтобы изменить его до того, как он будет отображен. Это означает, что вам не нужно указывать все аргументы при создании объекта Url, вместо этого вы можете просто создать URL адрес, а затем применить другие свойства позже.
Например, мы можем установить URL адрес как абсолютный, чтобы при выводе он содержал полный адрес сервера, а также путь. Без этого мы бы просто получили путь к визуализируемому объекту Url.
$url = Url::fromUri('user.logout');
$url->setAbsolute();
$string = $url->toString();
// https://www.example.ru/user/logout
При создании маршрутов, требующих параметров, с помощью метода fromUri(), вы можете установить эти параметры с помощью метода setRouteParameter().
$url = Url::fromUri('route:entity.node.canonical');
$url->setRouteParameter('node', 1);
Объект Url занимается только представлением URL. Если мы хотим вывести HTML ссылку, нам нужно использовать другой объект с именем Link.
Объект ссылки
Внутренний класс \Drupal\Core\Link используется для отображения ссылок. Этот класс должен использоваться статически точно так же, как объект Url, поэтому его также необходимо добавлять в начало любого файла, который его использует.
use \Drupal\Core\Link;
Как и в случае с объектом Url, существует несколько способов создания объекта Link.
$link = new Link('Link', $url);
В качестве альтернативы вы можете использовать метод fromTextAndUrl() для создания объекта Link с теми же параметрами, что и у конструктора.
$link = Link::fromTextAndUrl(t('Link'), $url);
Можно сгенерировать ссылку без предварительного создания объекта Url, используя статический метод createFromRoute().
$link = Link::createFromRoute(t('Link'), 'user.logout');
Если вы хотите передать параметры или опции этому методу, то это можно сделать с помощью третьего и четвертого параметров соответственно.
$link = Link::createFromRoute(t('Link'), 'entity.node.canonical', ['node' => 1], ['parameter' => '123']);
Имея в руках объект Link, мы можем сделать с ним пару вещей.
Использование объекта Link
Основная функция объекта Link заключается в отображении ссылки как элемента HTML с использованием предоставленного текста и URL адреса для создания ссылки.
Чтобы вывести полную HTML ссылку с использованием параметров, вы можете использовать метод getGeneratedLink().
$url = Url::fromUri('route:user.logout');
$link = new Link('Log Out', $url);
$string = $link->toString(); $string->getGeneratedLink();
// <a href="/ru/user/logout">Log Out</a>
В качестве альтернативы вы можете использовать метод toRenderable() для создания отображаемого массива. Это полезно, если вы хотите вывести ссылку как часть вывода контроллера или формы, поскольку вы можете просто добавить ссылку к выводу.
$url = Url::fromUri('route:user.logout');
$link = new Link('Log Out', $url);
$renderable = $link->toRenderable();
$build['link'] = $renderable;
Имея готовый для рендеринга массив, у нас также есть возможность добавлять атрибуты к HTML ссылке. Следующий пример добавит класс в вывод HTML.
$url = Url::fromUri('route:user.logout');
$link = new Link('Log Out', $url);
$renderable = $link->toRenderable();
$build['link'] = $renderable;
$build['link']['attributes'] = ['class' => ['some-class']];
Добавляя классы и другие элементы, вы получаете небольшой контроль над HTML кодом ссылки из-за пределов уровня шаблона приложения Drupal.
Служба диспетчера псевдонимов путей
Служба path_alias.manager часто оказывается полезной, когда вы хотите преобразовать внутренний путь объекта в псевдоним этого пути. Он часто используется в тех же ситуациях, что и классы Link и Url, поэтому имеет смысл упомянуть его при создании URL адресов.
Чтобы использовать эту службу, вы должны либо внедрить ее через внедрение зависимостей, либо захватить службу с помощью загрузчика службы.
/** @var \Drupal\path_alias\AliasManager $aliasManager */
$aliasManager = \Drupal::service('path_alias.manager');
С помощью этой службы мы теперь можем преобразовать псевдоним пути во внутренний путь, используя метод getPathByAlias(). Например, мы можем преобразовать псевдоним узла во внутренний путь узла (в данном случае это /node/1).
$path = $aliasManager->getPathByAlias('/some/alias/of/a/node');
// /node/1
Противоположный процесс можно выполнить для преобразования пути в псевдоним с помощью метода getAliasByPath().
$alias = $aliasManager->getAliasByPath('/node/1', 'ru');
// /some/alias/of/a/node
Я редко пользуюсь этой службой, так как классы Url и Link поддерживают псевдонимы, но я публикую её здесь, так как она может быть полезна в некоторых ситуациях. Вы также увидите несколько примеров, в которых говорится, что именно так можно получить псевдоним узла, что технически правильно, но проще сделать это, используя сам узел.
Текущая служба пути
Хотя вы можете получить текущий путь из объектов Url и Request, также существует служба под названием «path.current», которую вы можете использовать для получения текущего пути к запрошенной странице.
/** @var \Drupal\Core\Path\CurrentPathStack $pathCurrentService */ $pathCurrentService = \Drupal::service('path.current');
$path = $pathCurrentService->getPath();
// /some/requested/path
Хотя это полезно, вы не должны полагаться на путь для обнаружения определенных страниц. Лучше использовать маршрут, чтобы найти текущий используемый маршрут. Это более точный подход и даст более надежные результаты.
Служба сопоставления текущего маршрута
Для сопоставления используемого в настоящее время маршрута существует служба «current_route_match». Вы можете использовать эту службу для получения информации об используемом в настоящее время маршруте, в том числе о том, какие параметры были переданы маршруту.
Чтобы получить текущее имя маршрута, вы можете использовать метод службы getRouteName().
/** @var \Drupal\Core\Routing\CurrentRouteMatch $currentRouteMatchService */
$currentRouteMatchService = \Drupal::service('current_route_match');
$currentRouteMatchService->getRouteName();
Если вы хотите использовать эту службу для преобразования маршрута в объект Url, вы можете использовать метод fromRouteMatch() в классе Url. Этот метод принимает объект \Drupal\Core\Routing\RouteMatch, который мы можем получить из службы current_route_match с помощью метода getCurrentRouteMatch().
Вот пример использования различных компонентов для создания объекта Url для текущего маршрута.
/** @var \Drupal\Core\Routing\CurrentRouteMatch $currentRouteMatchService */
$currentRouteMatchService = \Drupal::service('current_route_match');
$route = Url::fromRouteMatch($currentRouteMatchService->getCurrentRouteMatch());
getCurrentRouteMatch() является оболочкой функции RouteMatch::createFromRequest() и дает нам удобный способ создания объекта RouteMatch.
Другие способы вывода ссылок
Есть несколько других механизмов, о которых следует помнить при создании URL адресов и вывода ссылок.
Объекты, поддерживающие связь
Если вы работаете с сущностями, хорошей новостью является то, что многие типы сущностей имеют свободный доступ к методам toUrl() и toLink(). Эти методы возвращают URL адрес или ссылку, связанные с загруженным в данный момент объектом.
$node = Node::load(1);
$url = $node->toUrl();
$link = $node->toLink();
Затем вы можете использовать объекты Url и Link для отображения ссылок выше.
Ссылки в переведенных строках
При использовании методов перевода (либо t(), либо $this->t()) вы можете использовать объект Url для вставки правильной ссылки в текст.
Вот пример этого в действии.
$url = \Drupal\Core\Url::fromRoute('entity.node.canonical', ['node' => 1]); $string = t('Link to an <a href="@url">entity</a>', ['@url' => $url->toString()]);
Ссылки в шаблонах Twig
Если вам нужно добавить маршрутизируемую ссылку непосредственно в шаблон, механизм Twig имеет доступ к объекту Url, поэтому вы можете использовать его для создания ссылки таким же образом. По умолчанию объект Url при рендеринге запускает метод toString(), поэтому этот метод используется в шаблонах Twig.
Например, вы можете вывести простую ссылку на любой маршрут на сайте, используя следующий синтаксис.
<a href="{{url('user.logout'}}"> {{ 'Log Out'|t }} </a>
Если вы хотите вывести ссылку на объект, вы также можете ввести параметры в маршрут, используя следующий синтаксис.
<a href="{{url('entity.node.canonical', {'node': node.id() }) }}"> {{ 'Link to a node'|t }} </a>
Заключение
Используя объекты Link и Url, вы можете создавать ссылки любым удобным для вас способом. Понимание того, как использовать эти два объекта, является ключевым, если вы хотите создать эти элементы.
Как я сказал в начале, создание URL адресов и ссылок зависит от контекста, поэтому многое из того, что я сказал здесь, может измениться в зависимости от ситуации, в которой вы находитесь. Не стесняйтесь добавлять комментарии ниже.