1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Spatie\Pjax\Middleware; |
4
|
|
|
|
5
|
|
|
use Closure; |
6
|
|
|
use Illuminate\Http\Request; |
7
|
|
|
use Illuminate\Http\Response; |
8
|
|
|
use Symfony\Component\DomCrawler\Crawler; |
9
|
|
|
|
10
|
|
|
class FilterIfPjax |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* The DomCrawler instance. |
14
|
|
|
* |
15
|
|
|
* @var \Symfony\Component\DomCrawler\Crawler |
16
|
|
|
*/ |
17
|
|
|
protected $crawler; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Whether the required filters have been applied. |
21
|
|
|
* |
22
|
|
|
* @var bool |
23
|
|
|
*/ |
24
|
|
|
private $filtered = false; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Handle an incoming request. |
28
|
|
|
* |
29
|
|
|
* @param \Illuminate\Http\Request $request |
30
|
|
|
* @param \Closure $next |
31
|
|
|
* |
32
|
|
|
* @return mixed |
33
|
|
|
*/ |
34
|
|
|
public function handle(Request $request, Closure $next) |
35
|
|
|
{ |
36
|
|
|
$response = $next($request); |
37
|
|
|
|
38
|
|
|
if (!$request->pjax() || $response->isRedirection()) { |
39
|
|
|
return $response; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
$this->filter($response, $request, function($response, $request) { |
43
|
|
|
$this->requiredFilter($response, $request); |
44
|
|
|
}); |
45
|
|
|
|
46
|
|
|
if (! $this->isFiltered()) { |
47
|
|
|
$this->requiredFilter($response, $request); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
return $response; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Easily add extra filters for PJAX requests. |
55
|
|
|
* |
56
|
|
|
* @param \Illuminate\Http\Response $response |
57
|
|
|
* @param \Illuminate\Http\Request $request |
58
|
|
|
*/ |
59
|
|
|
protected function filter(Response $response, Request $request, Closure $filter) |
60
|
|
|
{ |
61
|
|
|
$filter($response, $request); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Run the required filters. |
66
|
|
|
* |
67
|
|
|
* @return $this |
68
|
|
|
*/ |
69
|
|
|
private function requiredFilter(Response $response, Request $request) |
70
|
|
|
{ |
71
|
|
|
$this->filterResponse($response, $request->header('X-PJAX-Container')) |
|
|
|
|
72
|
|
|
->setUriHeader($response, $request) |
73
|
|
|
->setVersionHeader($response, $request); |
74
|
|
|
|
75
|
|
|
$this->filtered = true; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Checks if the default PJAX filters have been applied. |
80
|
|
|
* |
81
|
|
|
* @return bool |
82
|
|
|
*/ |
83
|
|
|
private function isFiltered() |
84
|
|
|
{ |
85
|
|
|
return $this->filtered; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* @param \Illuminate\Http\Response $response |
90
|
|
|
* @param string $container |
91
|
|
|
* |
92
|
|
|
* @return $this |
93
|
|
|
*/ |
94
|
|
|
private function filterResponse(Response $response, $container) |
95
|
|
|
{ |
96
|
|
|
$crawler = $this->getCrawler($response); |
97
|
|
|
|
98
|
|
|
$response->setContent( |
99
|
|
|
$this->makeTitle($crawler). |
100
|
|
|
$this->fetchContainer($crawler, $container) |
101
|
|
|
); |
102
|
|
|
|
103
|
|
|
return $this; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @param \Symfony\Component\DomCrawler\Crawler $crawler |
108
|
|
|
* |
109
|
|
|
* @return null|string |
110
|
|
|
*/ |
111
|
|
|
private function makeTitle(Crawler $crawler) |
112
|
|
|
{ |
113
|
|
|
$pageTitle = $crawler->filter('head > title'); |
114
|
|
|
|
115
|
|
|
if (!$pageTitle->count()) { |
116
|
|
|
return; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
return "<title>{$pageTitle->html()}</title>"; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* @param \Symfony\Component\DomCrawler\Crawler $crawler |
124
|
|
|
* @param string $container |
125
|
|
|
* |
126
|
|
|
* @return string |
127
|
|
|
*/ |
128
|
|
|
private function fetchContainer(Crawler $crawler, $container) |
129
|
|
|
{ |
130
|
|
|
$content = $crawler->filter($container); |
131
|
|
|
|
132
|
|
|
if (!$content->count()) { |
133
|
|
|
abort(422); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
return $content->html(); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @param \Illuminate\Http\Response $response |
141
|
|
|
* @param \Illuminate\Http\Request $request |
142
|
|
|
*/ |
143
|
|
|
private function setUriHeader(Response $response, Request $request) |
144
|
|
|
{ |
145
|
|
|
$response->header('X-PJAX-URL', $request->getRequestUri()); |
146
|
|
|
|
147
|
|
|
return $this; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param \Illuminate\Http\Response $response |
152
|
|
|
* @param \Illuminate\Http\Request $request |
153
|
|
|
*/ |
154
|
|
|
private function setVersionHeader(Response $response, Request $request) |
|
|
|
|
155
|
|
|
{ |
156
|
|
|
$crawler = $this->getCrawler($response); |
157
|
|
|
$node = $crawler->filter('head > meta[http-equiv]'); |
158
|
|
|
|
159
|
|
|
if ($node->count()) { |
160
|
|
|
$response->header('X-PJAX-Version', $node->attr('content')); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $this; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Get the DomCrawler instance. |
168
|
|
|
* |
169
|
|
|
* @param \Illuminate\Http\Response $response |
170
|
|
|
* |
171
|
|
|
* @return \Symfony\Component\DomCrawler\Crawler |
172
|
|
|
*/ |
173
|
|
|
protected function getCrawler(Response $response) |
174
|
|
|
{ |
175
|
|
|
if ($this->crawler) { |
176
|
|
|
return $this->crawler; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
return $this->crawler = new Crawler($response->getContent()); |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.