Slim Framework 3 — использование маршрутизатора в глобальном шаблоне

#php #slim

#php #slim

Вопрос:

Я относительно новичок в Slim Framework 3. Одна вещь, которую я пытаюсь понять, это как использовать маршрутизатор, $this->router , в «глобальном» шаблоне.

Под этим я подразумеваю шаблон, такой как меню навигации — то, что появляется на каждой странице.

Для шаблонов я использую библиотеку «php-view» в соответствии с примером учебника, который я установил с:

composer require slim/php-view

В моем каталоге шаблонов у меня есть файл с именем nav.php , в котором я хочу выводить свои ссылки.

Я понимаю, как вызвать маршрутизатор следующим образом

 <a href="<?=$router->pathFor('sign-up')?>">Sign Up</a>
  

Но… в примере руководства показано только, как вы передадите эту ссылку из 1 отдельного места, например $app->get('/sign-up' ... })->setName("sign-up");

Как вы можете использовать маршрутизатор глобально в любом шаблоне, не передавая его в каждый отдельный URL-адрес в качестве параметра?

Я больше знаком с такими фреймворками, как CakePHP, где есть «AppController», который позволяет вам устанавливать вещи глобально, т. Е. Доступно в каждом запросе. Я не знаю, так ли это делается в Slim, но это тот эффект, который мне нужен.

Ответ №1:

Ну, вы можете передать его как переменную шаблона.

При создании экземпляра или регистрации PhpRenderer в контейнере у вас есть несколько вариантов определения «глобальной» переменной, то есть переменной, доступной во всех ваших шаблонах:

 // via the constructor
$templateVariables = [
    "router" => "Title"
];
$phpView = new PhpRenderer("./path/to/templates", $templateVariables);

// or setter
$phpView->setAttributes($templateVariables);

// or individually
$phpView->addAttribute($key, $value);
  

Предполагая, что вы регистрируетесь PhpRenderer через Pimple:

 <?php
// Create application instance
$app = new SlimApp();

// Get container
$container = $app->getContainer();

// Register PhpRenderer in the container
$container['view'] = function ($container) {

    // Declaring "global" variables
    $templateVariables = [
        'router' => $container->get('router')
    ];

    // And passing the array as second argument to the contructor
    return new SlimViewsPhpRenderer('path/to/templates/with/trailing/slash/', $templateVariables);
};
  

Комментарии:

1. Это, вероятно, лучший способ сделать это. Если вы настраиваете средство визуализации на фабрике контейнеров, вы можете получить экземпляр маршрутизатора из контейнера и передать его в средство визуализации в качестве переменной шаблона

2. @geggleto Проблема с этим заключается в том, что он передает весь объект маршрутизатора в каждый шаблон. Если я делаю var_dump($router); это в своих шаблонах, появляется огромный массив, который содержит вещи, которые мне не нужны, включая учетные данные БД. Не уверен, есть ли более эффективный способ сделать это, где вы можете просто получить доступ к именованным маршрутам?

3. Поскольку объекты по умолчанию передаются по ссылке, в этом решении нет снижения производительности. Если у вас много непримитивных шаблонов, рассмотрите возможность использования компонента Slim Twig-view : в нем используется библиотека Twig, которая намного мощнее, чем 150 строк для одного класса PhpRenderer .

4. Как автор PhpRenderer, я одобряю приведенное выше сообщение 😉 PhpRenderer был коротким путем, чтобы заставить людей использовать шаблоны. Если вы достигли этой стадии разработки, шаблоны Twig имеют больше смысла… Хотя я буду добавлять больше функций в PHP-View в течение следующих нескольких месяцев

Ответ №2:

 <?php namespace AppHelpers;

/********************/
//LinksHelper.php
/********************/

use InteropContainerContainerInterface;

class LinksHelper
{  
    protected $ci;

    public function __construct(ContainerInterface $container){
      $this->ci = $container;
    }

    public function __get($property){
        if ($this->ci->has($property)) {
          return $this->ci->get($property);
        }
    }

    public function pathFor($name, $data = [], $queryParams = [], $appName = 'default')
    {
        return $this->router->pathFor($name, $data, $queryParams);
    }

    public function baseUrl()
    {
        if (is_string($this->uri)) {
            return $this->uri;
        }
        if (method_exists($this->uri, 'getBaseUrl')) {
            return $this->uri->getBaseUrl();
        }
    }

    public function isCurrentPath($name, $data = [])
    {
        return $this->router->pathFor($name, $data) === $this->uri->getPath();
    }

    public function setBaseUrl($baseUrl)
    {
        $this->uri = $baseUrl;
    }
}

?>

<?php
/********************/
//dependencies.php
/********************/

$container['link'] = function ($c) {
  return new AppHelpersLinksHelper($c);
};

// view renderer
$container['view'] = function ($c) {
    $settings = $c->get('settings');
    $view = new AppViewsMyPhpRenderer($settings['renderer']['template_path']);
    $view->setLayout('default.php');
    //$view->addAttribute('title_for_layout', $settings['title_app'] .' :: ');  
    $view->setAttributes([
      'title_for_layout'=>$settings['title_app'] .' :: ',
      'link' => $c->get('link')
    ]);  
    return $view;
};
?>


<?php
/********************/
//routes.php
/********************/


use PsrHttpMessageServerRequestInterface as Request;
use PsrHttpMessageResponseInterface as Response;

$app->get('/', function (Request $request, Response $response, array $args) {
    return $this->view->render($response, 'your_view.php');
})->setName('home');
?>

<?php
/********************/
//your_view.php
/********************/
?>

<a href="<?=$link->pathFor('home')?>">Home</a>
  

Комментарии:

1. отличная работа! это отлично работает для меня! я использовал $link-> pathFor() префектно; но $link-> baseUrl() не работает! как сделать это правильно?

Ответ №3:

Вы должны создать новый класс, например, MainMenu, и там вы должны создать массив со всеми путями для menu . Объект MainMenu должен возвращать массив с метками и путями, а затем вы можете передать этот массив в свое представление:

 $menu = (new MainMenu())->buildMenu();
$response = $this->view->render($response, "index.phtml", [
    'menu' => $menu
]);
  

Затем в вашем *.phtml файле у вас есть доступ к $menu переменной. Но что, если вы не хотите повторять этот код в каждом маршруте?

Используйте промежуточные программы. Вы можете передать переменную из промежуточного программного обеспечения с помощью

 $request = $request->withAttribute('foo', 'bar');
  

и извлеките

 $foo = $request->getAttribute('foo');