PagerfantaExtension::createRouteGenerator()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 8.5777
c 0
b 0
f 0
cc 6
nc 4
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Pagerfanta package.
5
 *
6
 * (c) Pablo Díez <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace WhiteOctober\PagerfantaBundle\Twig;
13
14
use Pagerfanta\PagerfantaInterface;
15
use Pagerfanta\View\ViewFactory;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpFoundation\RequestStack;
18
use Symfony\Component\PropertyAccess\PropertyAccess;
19
use Symfony\Component\PropertyAccess\PropertyPath;
20
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
21
use Twig\Extension\AbstractExtension;
22
use Twig\TwigFunction;
23
24
/**
25
 * PagerfantaExtension.
26
 *
27
 * @author Pablo Díez <[email protected]>
28
 */
29
class PagerfantaExtension extends AbstractExtension
30
{
31
    private $defaultView;
32
    private $viewFactory;
33
    private $router;
34
    private $requestStack;
35
    private $request;
36
37
    public function __construct($defaultView, ViewFactory $viewFactory, UrlGeneratorInterface $router, RequestStack $requestStack = null)
38
    {
39
        $this->defaultView = $defaultView;
40
        $this->viewFactory = $viewFactory;
41
        $this->router = $router;
42
        $this->requestStack = $requestStack;
43
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48
    public function getFunctions()
49
    {
50
        return array(
51
            new TwigFunction('pagerfanta', array($this, 'renderPagerfanta'), array('is_safe' => array('html'))),
52
            new TwigFunction('pagerfanta_page_url', array($this, 'getPageUrl')),
53
        );
54
    }
55
56
    /**
57
     * Renders a pagerfanta.
58
     *
59
     * @param PagerfantaInterface $pagerfanta The pagerfanta.
60
     * @param string|array        $viewName   The view name.
61
     * @param array               $options    An array of options (optional).
62
     *
63
     * @return string The pagerfanta rendered.
64
     */
65
    public function renderPagerfanta(PagerfantaInterface $pagerfanta, $viewName = null, array $options = array())
66
    {
67
        if (is_array($viewName)) {
68
            list($viewName, $options) = array(null, $viewName);
69
        }
70
71
        $viewName = $viewName ?: $this->defaultView;
72
73
        $routeGenerator = $this->createRouteGenerator($options);
74
75
        return $this->viewFactory->get($viewName)->render($pagerfanta, $routeGenerator, $options);
76
    }
77
78
    /**
79
     * Generates the url for a given page in a pagerfanta instance.
80
     *
81
     * @param \Pagerfanta\PagerfantaInterface $pagerfanta
82
     * @param $page
83
     * @param array $options
84
     *
85
     * @return string The url of the given page
86
     *
87
     * @throws \InvalidArgumentException
88
     */
89
    public function getPageUrl(PagerfantaInterface $pagerfanta, $page, array $options = array())
90
    {
91
        if ($page < 0 || $page > $pagerfanta->getNbPages()) {
92
            throw new \InvalidArgumentException("Page '{$page}' is out of bounds");
93
        }
94
95
        $routeGenerator = $this->createRouteGenerator($options);
96
97
        return $routeGenerator($page);
98
    }
99
100
    /**
101
     * Creates an anonymous function which returns the URL for a given page.
102
     *
103
     * @param array $options
104
     *
105
     * @return callable
106
     *
107
     * @throws \Exception
108
     */
109
    private function createRouteGenerator($options = array())
110
    {
111
        $options = array_replace(array(
112
                'routeName'     => null,
113
                'routeParams'   => array(),
114
                'pageParameter' => '[page]',
115
                'omitFirstPage' => false
116
            ), $options);
117
118
        $router = $this->router;
119
120
        if (null === $options['routeName']) {
121
            $request = $this->getRequest();
122
123
            $options['routeName'] = $request->attributes->get('_route');
124
            if ('_internal' === $options['routeName']) {
125
                throw new \Exception('PagerfantaBundle can not guess the route when used in a subrequest');
126
            }
127
128
            // make sure we read the route parameters from the passed option array
129
            $defaultRouteParams = array_merge($request->query->all(), $request->attributes->get('_route_params', array()));
130
131
            if (array_key_exists('routeParams', $options)) {
132
                $options['routeParams'] = array_merge($defaultRouteParams, $options['routeParams']);
133
            } else {
134
                $options['routeParams'] = $defaultRouteParams;
135
            }
136
        }
137
138
        $routeName = $options['routeName'];
139
        $routeParams = $options['routeParams'];
140
        $pagePropertyPath = new PropertyPath($options['pageParameter']);
141
        $omitFirstPage = $options['omitFirstPage'];
142
143
        return function($page) use($router, $routeName, $routeParams, $pagePropertyPath, $omitFirstPage) {
144
            $propertyAccessor = PropertyAccess::createPropertyAccessor();
145
            if($omitFirstPage){
146
                $propertyAccessor->setValue($routeParams, $pagePropertyPath, $page > 1 ? $page : null);
147
            } else {
148
                $propertyAccessor->setValue($routeParams, $pagePropertyPath, $page);
149
            }
150
151
            return $router->generate($routeName, $routeParams);
152
        };
153
    }
154
155
    public function setRequest(Request $request = null)
156
    {
157
        $this->request = $request;
158
    }
159
160
    /**
161
     * @return Request|null
162
     */
163
    private function getRequest()
164
    {
165
        if ($this->requestStack && $request = $this->requestStack->getCurrentRequest()) {
166
            return $request;
167
        }
168
169
        return $this->request;
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function getName()
176
    {
177
        return 'pagerfanta';
178
    }
179
}
180