Slim Framework + Turbolinks


Some notes for my Slim + Turbolinks

  1. Download turbolinks.js
  2. Download jquery.turbolinks.js
  3. Load the js files like
1
2
3
4
5

<script src="{{ baseUrl() }}/static/vendor/jquery/jquery.min.js"></script>
<script src="{{ baseUrl() }}/static/vendor/turbolinks.js"></script>
<script src="{{ baseUrl() }}/static/client/js/default.js"></script>

  1. If you need Turbolinks event, just like:
1
2
3
$(document).on('page:fetch',   function() { NProgress.start(); });
$(document).on('page:change', function() { NProgress.done(); });
$(document).on('page:restore', function() { NProgress.remove(); });
  1. Modify app.php like
1
2
3
4
5
6
<?php
use Hand\Middlewares\TurboLinks;

$slim = new Slim\Slim();
$slim->add(new TurboLinks());
$slim->run();
  1. Save to path: App\Middlewares
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?php
namespace App\Middlewares;

class Turbolinks extends \Slim\Middleware {

const REQUEST_METHOD_COOKIE_ATTR_NAME = 'request_method';
const ORIGIN_REQUEST_HEADER = 'X-XHR-Referer';
const ORIGIN_RESPONSE_HEADER = 'Location';
const REDIRECT_RESPONSE_HEADER = 'X-XHR-Redirected-To';
const REDIRECT_SESSION_ATTR_NAME = '_turbolinks_redirect_to';

public function call() {
$app = $this->app;

if ($this->canHandleRedirect($app->request) === false) {
$this->next->call();
}else{
$session = isset($_SESSION) === true ? $_SESSION : [];

if (array_key_exists(self::REDIRECT_SESSION_ATTR_NAME, $session) === true) {
$redirect_to = $session[self::REDIRECT_SESSION_ATTR_NAME];

unsset($session[self::REDIRECT_SESSION_ATTR_NAME]);

$app->response->headers->set(self::REDIRECT_RESPONSE_HEADER, $redirect_to);
}

if ($app->response->isRedirect() && $app->response->headers->has('Location')) {
$_SESSION[self::REDIRECT_SESSION_ATTR_NAME] = $app->response->headers->get('Location');
}

$this->next->call();
}
}

private function addRequestMethodCookie($request, $response) {
$response->setCookie(self::REQUEST_METHOD_COOKIE_ATTR_NAME, $request->getMethod());
}

private function modifyStatusCode($request, $response) {
if ($request->headers->has(self::ORIGIN_REQUEST_HEADER) === true) {
if ($response->headers->has(self::ORIGIN_RESPONSE_HEADER) === true) {
if ($this->haveSameOrigin($request, $response) === false) {
$app->response->setStatus(403);
}
}
}
}

private function canHandleRedirect($request) {
$session = isset($_SESSION) === true ? $_SESSION : null;

return $session instanceof SessionInterface && $request->headers->has(self::ORIGIN_REQUEST_HEADER);
}

private function getUrlOrigin($url) {
return [
parse_url($url, PHP_URL_SCHEME),
parse_url($url, PHP_URL_HOST),
parse_url($url, PHP_URL_PORT),
];
}

private function haveSameOrigin($request, $response) {
$request_origin = $this->getUrlOrigin($request->headers->get(self::ORIGIN_REQUEST_HEADER));
$response_origin = $this->getUrlOrigin($response->headers->get(self::ORIGIN_RESPONSE_HEADER));

return $request_origin == $response_origin;
}

}