Slim Framework 3 - 在全局模板中使用路由器

Slim Framework 3 - using router in a global template

我对 Slim Framework 3 比较陌生。我想了解的一件事是如何在 "global" 模板中使用路由器 $this->router

我的意思是这是一个模板,例如导航菜单 - 每个页面上都会出现的东西。

对于模板,我根据我安装的 example tutorial 使用 "php-view" 库:

composer require slim/php-view

在我的模板目录中,我有一个名为 nav.php 的文件,我想在其中输出我的 links。

我明白怎么调用路由器了

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

但是...示例教程仅显示了如何从 1 个单独的位置传递 link,例如$app->get('/sign-up' ... })->setName("sign-up");

如何在任何模板中全局使用路由器,而不将其作为参数传递给每个单独的 URL 路由?

我更熟悉像 CakePHP 这样的框架,其中有一个 "AppController" 允许您全局设置,即在每个请求中可用。我不知道在 Slim 中是不是这样做的,但这就是我想要的效果。

您应该创建一个新的 class,例如MainMenu,在那里你应该创建一个包含菜单所有路径的数组。 MainMenu 的对象应该 return 一个带有标签和路径的数组,然后您可以将该数组传递给您的视图:

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

然后在您的 *.phtml 文件中您可以访问 $menu 变量。但是,如果您不想在每条路线中重复该代码怎么办?

使用middlewares。您可以使用

从中间件传递变量
$request = $request->withAttribute('foo', 'bar');

并检索

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

好吧,你可以将其传递为 template variable

当您在容器中实例化或注册 PhpRenderer 时,您有多个选项来定义 "global" 变量,即在所有模板中都可以访问的变量:

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

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

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

假设您通过 Pimple 注册PhpRenderer

<?php
// Create application instance
$app = new \Slim\App();

// 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 \Slim\Views\PhpRenderer('path/to/templates/with/trailing/slash/', $templateVariables);
};
<?php namespace App\Helpers;

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

use Interop\Container\ContainerInterface;

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 \App\Helpers\LinksHelper($c);
};

// view renderer
$container['view'] = function ($c) {
    $settings = $c->get('settings');
    $view = new App\Views\MyPhpRenderer($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 Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface 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>