简体   繁体   English

使用Slim 3对Eloquent-5.3进行分页

[英]Pagination with Eloquent-5.3 using Slim 3

Here's my code for the pagination: 这是我的分页代码:

Controller: 控制器:

public function index($request, $response) {

    $current_page = $request->getParam('page');

    Paginator::currentPageResolver(function() use ($current_page) {
        return $current_page;
    });

    $routes = $this->route->paginate(2);

    return $this->view->render($response, 'dashboard/dashboard.twig', [
        'routes' => $routes
    ]);
}

View: 视图:

{% for route in routes %}
    {{ route.route_name }}<br>
{% endfor %}

There's no problem with that when I run the browser. 当我运行浏览器时没有问题。 It also works whenver I add page parameter in the url. 当我在网址中添加page参数时,它也有效。

在此输入图像描述

But when I try to add the links method in the paginate object. 但是当我尝试在paginate对象中添加links方法时。

{% for route in routes %}
    {{ route.route_name }}<br>
{% endfor %}

{{ routes.links() }} {# <--- This one #}

It prompts me an error 它提示我一个错误

Message: Call to a member function make() on null 消息:在null上调用成员函数make()

File: C:\\xampp\\htdocs...\\vendor\\illuminate\\pagination\\LengthAwarePaginator.php 文件:C:\\ xampp \\ htdocs ... \\ vendor \\ illuminate \\ pagination \\ LengthAwarePaginator.php

Update: 更新:

When I try to echo the links() method inside the Controller. 当我尝试回显Controller内的links()方法时。 I found this error. 我发现了这个错误。

$routes = $this->route->paginate(5);
echo $routes->links();
die();

Warning: call_user_func() expects parameter 1 to be a valid callback, no array or string given in C:\\xampp\\htdocs...\\vendor\\illuminate\\pagination\\AbstractPaginator.php on line 377 警告:call_user_func()期望参数1是有效的回调,没有在第377行的C:\\ xampp \\ htdocs ... \\ vendor \\ illuminate \\ pagination \\ AbstractPaginator.php中给出的数组或字符串

Then I checked the source code, it's this one. 然后我检查了源代码,就是这个。

/**
 * Get an instance of the view factory from the resolver.
 *
 * @return \Illuminate\Contracts\View\Factory
 */
public static function viewFactory()
{
    return call_user_func(static::$viewFactoryResolver);
}

Any solution for this? 对此有何解决方案?

This method works in 5.2, referring to this link. 这个方法适用于5.2,参考这个链接。

Pagination with Twig and Eloquent-5.2 用Twig和Eloquent-5.2分页

But unfortunely, it doesn't work anymore. 但不幸的是,它不再起作用了。

In PHP 7 you can create anonymous class for register it for use in viewVactory: 在PHP 7中,您可以创建匿名类以注册它以在viewVactory中使用:

$view = $this->container->get('view');

$view->getEnvironment()->addTest(new Twig_SimpleTest('string', function($value) {
    return is_string($value);
}));

\Illuminate\Pagination\Paginator::viewFactoryResolver(function() use ($view) {
    return new class($view) {
        private $view;
        private $template;
        private $data;

        public function __construct(\Slim\Views\Twig $view)
        {
            $this->view = $view;
        }

        public function make(string $template, $data = null)
        {
            $this->template = $template;
            $this->data = $data;
            return $this;
        }

        public function render()
        {
            return $this->view->fetch($this->template, $this->data);
        }
    };
});

\Illuminate\Pagination\Paginator::currentPageResolver(function() use ($request) {
    return $request->getParam('page');
});

return $view->render($response, 'list.twig', [
    'items' => Material::paginate(10),
]);

In list.twig : list.twig

{{ items.render('pagination.twig') | raw }}

In pagination.twig : pagination.twig

{% if paginator.hasPages() %}
    <ul class="pagination">
        {% for element in elements %}
            {% if element is string %}
                <li class="disabled"><span>{{ element }}</span></li>
            {% endif %}

            {% if element is iterable %}
                {% for page, url in element %}
                    {% if page == paginator.currentPage() %}
                        <li class="active"><span>{{ page }}</span></li>
                    {% else %}
                        <li><a href="{{ url }}">{{ page }}</a></li>
                    {% endif %}
                {% endfor %}
            {% endif %}
        {% endfor %}
    </ul>
{% endif %}

I had to use a combination of the answers above to get something fully working. 我不得不使用上面的答案组合来完成一些工作。 I'll post my solution here in case it helps others. 我会在这里发布我的解决方案,以防它帮助别人。

This is Wesley's template, but upgraded to work with bootstrap 4. And as a bonus, it doesn't need the middleware to set any global variables. 这是Wesley的模板,但升级为使用bootstrap 4.作为奖励,它不需要中间件来设置任何全局变量。

// pagination.twig
{% if data is not empty and data.lastPage > 1 %}

{# Pagination shows a "window" of links to the left and right of the current page #}
{% set num_visible_pages = 20 %}

<ul class="pagination">

  <li class="page-item {{ (data.currentPage == 1) ? 'disabled' : '' }}">
    <a class="page-link" href="{{ data.url(1) }}">First</a>
  </li>

  {% for page_number in 1..(data.lastPage) %}
    {% set half_visible_links = num_visible_pages / 2 | round %}
    {% set from = data.currentPage - half_visible_links %}
    {% set to = data.currentPage + half_visible_links %}

    {# if near beginning of pages, extend end to ensure num_visible_pages are shown #}
    {% if data.currentPage < half_visible_links %}
      {# we can be sloppy because the loop iteration constrains-out-of-bounds values #}
      {% set to = (half_visible_links - data.currentPage) + to %}
    {% endif %}

    {# if near end of pages, extend beginning to ensure num_visible_pages are shown #}
    {% if (data.lastPage - data.currentPage) < half_visible_links %}
      {# we can be sloppy because the loop iteration constrains-out-of-bounds values #}
      {% set from = data.lastPage - num_visible_pages %}
    {% endif %}

    {# only print pages between "from" and "to" #}
    {% if from < page_number and page_number < to %}
      <li class="page-item {{ (data.currentPage == page_number) ? 'active' : '' }}">
        <a class="page-link" href="{{ data.url(page_number) }}">{{ page_number }}</a>
      </li>
    {% endif %}
  {% endfor %}

  <li class="page-item {{ (data.currentPage == data.lastPage) ? 'disabled' : '' }}">
    <a class="page-link" href="{{ data.url(data.lastPage) }}">Last</a>
  </li>

</ul>

{% endif %}

Which you can call in your twig template with something like this, where "items" is the result of the paginator query. 你可以在你的twig模板中调用这样的东西,其中“items”是paginator查询的结果。

{% include 'pagination.twig'
    with {data: items} only
%}

Then, you need to tell the Eloquent Paginator how to get the "page" from the url (otherwise you'll be stuck on page 1). 然后,你需要告诉Eloquent Paginator如何从网址获取“页面”(否则你将被困在第1页)。 You can do this by calling currentPageResolver() sometime before your paginator() query. 您可以通过在paginator()查询之前调用currentPageResolver()来执行此操作。 For me, I just slipped it into some middleware so it's always defined. 对我来说,我只是把它放到一些中间件中,所以它总是被定义。

<?php

/**
 * Tells the Eloquent Paginator how to get the current page
 */

namespace App\Middleware;

class Pagination {

    public function __invoke($request, $response, $next)
    {
        \Illuminate\Pagination\Paginator::currentPageResolver(function() use ($request) {
            return $request->getParam('page');
        });

        return $next($request, $response);
    }

}

And let Slim know about the middleware it in your app setup. 让Slim在您的应用设置中了解它的中间件。

$app->add(new App\Middleware\Pagination);

You may want to add more parameters to the url, such as sorting or toggle data. 您可能希望向网址添加更多参数,例如排序或切换数据。 You can still use $items->appends() to do so. 您仍然可以使用$items->appends()来执行此操作。 Note that the default path is to "/". 请注意,默认路径为“/”。 You can remove that with $items->withPath('') so links generated with ->url() will link to the current page. 您可以使用$items->withPath('')删除它,因此使用->url()生成的->url()将链接到当前页面。

As a temporary solution, it seems I can access the paginate object's methods. 作为临时解决方案,我似乎可以访问paginate对象的方法。 So I tried to find a laravel template of pagination around the internet. 所以我试图在互联网上找到一个分页的laravel模板。

Here's the solution that I came up with. 这是我提出的解决方案。

What it does is, it will only show if the array is not empty and obviously if it renders more than one page. 它的作用是,它只显示数组是否为空,显然它是否呈现多个页面。 (Depending on the number of pages you will set up in your pagination) (取决于您在分页中设置的页数)

And the template that I got from somewhere with modified functions that suited for my needs. 我从某个地方获得的模板具有适合我需要的修改功能。

{% if arrays is not empty and arrays.lastPage > 1 %}

    <div class="paginate-wrapper">

        <ul class="pagination">

            <li class="{{ (arrays.currentPage == 1) ? 'active' : '' }}">
                <a href="{{ uri.link }}{{ (uri.request_sent) ? '&' : '?' }}page=1">First</a>
            </li>

            {% for page_number in 1..(arrays.lastPage) %}

                {% set half_total_links = 7 / 2 | round %}
                {% set from = arrays.currentPage - half_total_links %}
                {% set to = arrays.currentPage + half_total_links %}

                {% if arrays.currentPage < half_total_links %}
                    {% set to = (half_total_links - arrays.currentPage) + to %}
                {% endif %}

                {% if (arrays.lastPage - arrays.currentPage) < half_total_links %}
                    {% set from = (half_total_links - (arrays.lastPage - arrays.currentPage) - 1) - to %}
                {% endif %}

                {% if from < page_number and page_number < to %}
                    <li class="{{ (arrays.currentPage == page_number) ? 'active' : '' }}">
                        <a href="{{ uri.link }}{{ (uri.request_sent) ? '&' : '?' }}page={{ page_number }}">{{ page_number }}</a>
                    </li>
                {% endif %}
            {% endfor %}

            <li class="{{ (arrays.currentPage == arrays.lastPage) ? 'active' : '' }}">
                <a href="{{ uri.link }}{{ (uri.request_sent) ? '&' : '?' }}page={{ arrays.lastPage }}">
                    Last
                </a>
            </li>
        </ul>
    </div>
{% endif %}

Here's my Middleware on Router. 这是我在路由器上的中间件。

namespace App\Middleware;

use Illuminate\Database\Capsule\Manager as DB;
use App\Models\Module\Module;

class RouterMiddleware extends Middleware {

    public function __invoke($request, $response, $next) {

        $uri          = $request->getUri();
        $current_path = $uri->getPath();
        $route        = $request->getAttribute('route');

        if ($route) {

            $route_name = $route->getName();

            $uri_page_parameter = $request->getParam('page');

            // We want to retrieve the whole url including all the get parameters to get the current url itself
            // Excluding page (pagination) parameter.
            if ($uri_page_parameter != '') {
                $uri = str_replace(['?page=' . $uri_page_parameter, '&page=' . $uri_page_parameter], '', $uri);
            }

            // We'll also check if the request has been sent using get method
            $uri_request_sent = explode('?', $uri);

            // Route Information
            $this->container->view->getEnvironment()->addGlobal('uri', [
                'link' => $uri,
                'request_sent' => (isset($uri_request_sent[1])) ? true : false
            ]);
            $this->container->view->getEnvironment()->addGlobal('current_route', $route_name);
            $this->container->view->getEnvironment()->addGlobal('current_path', $current_path);
        }

        $response = $next($request, $response);
        return $response;
    }
}

What it does is, every time you searched for something, when you change pages, all the request that you sent will not be gone. 它的作用是,每次搜索某些内容时,当您更改页面时,您发送的所有请求都不会消失。

in your controller, you can do this: 在你的控制器中,你可以这样做:

$routes = $this->route->paginate(5);
$window = Illuminate\Pagination\UrlWindow::make($routes);
$elements = [
    $window['first'],
    is_array($window['slider']) ? '...' : null,
    $window['slider'],
    is_array($window['last']) ? '...' : null,
    $window['last'],
];
// $this->twig is an instance of \Twig_Environment
// before render the template below, you should add `is_array` and `is_string` funcion to twig first
$this->twig->addFunction('is_string', new \Twig_SimpleFunction('is_string', function ($val) {
    return is_string($val);
}));
$this->twig->addFunction('is_array', new \Twig_SimpleFunction('is_array', function ($val) {
    return is_array($val);
}));
echo $this->twig->render(
        'pageNav.html',
        ['paginator' => $routes, 'elements' => array_filter($elements)]
    );

your template file(pageNav.html) will be like this: 您的模板文件(pageNav.html)将如下所示:

{% if paginator.hasPages %}
<ul class="am-pagination">
    {% if paginator.onFirstPage %}
    <li class="am-disabled"><span>&laquo;</span></li>
    {% else %}
    <li><a href="{{ paginator.previousPageUrl }}" rel="prev">&laquo;</a></li>
    {% endif %}

    {% for element in elements %}
        {% if is_string(element) %}
        <li class="am-disabled"><span>{{ element }}</span></li>
        {% endif %}

        {% if is_array(element) %}
            {% for page, url in element %}
            {% if paginator.currentPage == page %}
            <li class="am-active"><span>{{ page }}</span></li>
            {% else %}
            <li><a href="{{ url }}">{{ page }}</a></li>
            {% endif %}
            {% endfor %}
        {% endif %}
    {% endfor %}

    {% if paginator.hasMorePages %}
    <li><a href="{{ paginator.nextPageUrl }}" rel="next">&raquo;</a></li>
    {% else %}
    <li class="am-disabled"><span>&raquo;</span></li>
    {% endif %}
</ul>
{% endif %}

good luck:) 祝好运:)

there is a little problem: 有一点问题:

{% if (data.lastPage - data.currentPage) < half_total_links %}
    {% set from = (half_total_links - (data.lastPage - data.currentPage) - 1) - to %}
{% endif %}

when data.lastPage and data.currentPage are equal, the variable from is negative. data.lastPagedata.currentPage相等时,变量from为负数。

I have fixed so: 我修好了:

{% if from < 0 %}
  {% set from = pagination.page - half_total_links %}
{% endif %}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM