【问题标题】:Pagination with Eloquent-5.3 using Slim 3使用 Slim 3 使用 Eloquent-5.3 进行分页
【发布时间】:2017-03-16 16:50:13
【问题描述】:

这是我的分页代码:

控制器:

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
    ]);
}

查看:

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

当我运行浏览器时,这没有问题。每当我在 url 中添加 page 参数时,它也可以工作。

但是当我尝试在分页对象中添加links 方法时。

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

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

它提示我一个错误

消息:在 null 上调用成员函数 make()

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

更新:

当我尝试在 Controller 中回显 links() 方法时。我发现了这个错误。

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

警告:call_user_func() 期望参数 1 是一个有效的回调,在 C:\xampp\htdocs...\vendor\illuminate\pagination\AbstractPaginator.php 第 377 行中没有给出数组或字符串

然后我查了源码,就是这个。

/**
 * 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);
}

有什么解决办法吗?

此方法在5.2有效,参考此链接。

Pagination with Twig and Eloquent-5.2

但不幸的是,它不再起作用了。

【问题讨论】:

  • 你找到 5.3 的解决方案了吗?

标签: php pagination eloquent


【解决方案1】:

作为临时解决方案,我似乎可以访问分页对象的方法。于是我在网上找了一个laravel的分页模板。

这是我想出的解决方案。

它的作用是,它只会在数组不为空并且很明显它呈现多页时显示。 (取决于您将在分页中设置的页数)

以及我从某个地方获得的模板,其中包含适合我需要的修改功能。

{% 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 %}

这是我在路由器上的中间件。

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;
    }
}

它的作用是,每次你搜索某个东西,当你换页时,你发送的所有请求都不会消失。

【讨论】:

    【解决方案2】:

    在您的控制器中,您可以这样做:

    $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)]
        );
    

    您的模板文件(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 %}
    

    祝你好运:)

    【讨论】:

      【解决方案3】:

      在 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),
      ]);
      

      list.twig:

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

      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 %}
      

      【讨论】:

        【解决方案4】:

        我必须结合使用上述答案才能使某些东西完全正常工作。我会在此处发布我的解决方案,以防对其他人有所帮助。

        这是 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 %}
        

        你可以用类似这样的东西在你的树枝模板中调用它,其中“items”是分页器查询的结果。

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

        然后,您需要告诉 Eloquent Paginator 如何从 url 中获取“页面”(否则您将卡在第 1 页)。您可以通过在 paginator() 查询之前调用 currentPageResolver() 来做到这一点。对我来说,我只是将它放入一些中间件中,所以它总是被定义的。

        <?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);
            }
        
        }
        

        并让 Slim 了解它在您的应用设置中的中间件。

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

        您可能希望向 url 添加更多参数,例如排序或切换数据。您仍然可以使用$items-&gt;appends() 来执行此操作。请注意,默认路径是“/”。您可以使用$items-&gt;withPath('') 删除它,这样使用-&gt;url() 生成的链接将链接到当前页面。

        【讨论】:

        • 这行得通,但是大约 20 页,最后几页没有正确计算“发件人”数字,所以我将 {% set from = (half_total_links - (data.lastPage - data.currentPage) - 1) - to %} 替换为 {% set from = (data.currentPage) - half_total_links - 1 %}
        • 谢谢伊格纳西奥。不久前我遇到了一些错误,忘记更新这个答案。当您接近大量页面的末尾时也会出现问题。您的修复可能也适用于此问题的其他答案。
        【解决方案5】:

        有个小问题:

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

        data.lastPagedata.currentPage 相等时,变量from 为负数。

        我已经解决了:

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

        【讨论】:

          猜你喜欢
          • 2017-07-21
          • 1970-01-01
          • 2016-04-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-08
          • 2016-11-16
          相关资源
          最近更新 更多