├── .gitignore
├── .travis.yml
├── composer.json
├── phpunit.xml.dist
├── readme.md
├── src
└── Turbo
│ ├── Provider
│ ├── Fuel
│ │ └── Response.php
│ └── Laravel
│ │ └── TurboServiceProvider.php
│ └── Turbo.php
└── tests
└── TurboTests
└── TurboTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | ## MAC OS
2 | .DS_Store
3 |
4 | ## TEXTMATE
5 | *.tmproj
6 | tmtags
7 |
8 | ## EMACS
9 | *~
10 | \#*
11 | .\#*
12 |
13 | ## VIM
14 | *.swp
15 |
16 | ## PHPDoc files
17 | *.ini
18 |
19 | ## Composer
20 | composer.lock
21 | vendor
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.3
5 | - 5.4
6 | - 5.5
7 | - hhvm
8 |
9 | matrix:
10 | allow_failures:
11 | - php: hhvm
12 |
13 | before_script:
14 | - curl -s https://getcomposer.org/installer | php
15 | - php ./composer.phar install --dev --prefer-source
16 |
17 | script: phpunit --configuration phpunit.xml.dist
18 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rcrowe/turbo",
3 | "description": "Think turbolinks but for your PHP application. Powered by pjax.",
4 | "keywords": ["pjax", "turbolinks", "laravel", "fuelphp"],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Rob Crowe",
9 | "email": "hello@vivalacrowe.com"
10 | }
11 | ],
12 | "require": {
13 | "php": ">=5.3.0"
14 | },
15 | "autoload": {
16 | "psr-0": {
17 | "Turbo": "src/"
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Turbo
2 | =====
3 |
4 | Turbolinks but for your PHP application; powered by [PJAX](https://github.com/defunkt/jquery-pjax).
5 |
6 | [](https://travis-ci.org/rcrowe/Turbo)
7 |
8 | Installation
9 | ------------
10 |
11 | Turbo has only been tested installing through [Composer](http://getcomposer.org/).
12 |
13 | Add `rcrowe\turbo` as a requirement to composer.json:
14 |
15 | ```javascript
16 | {
17 | "require": {
18 | "rcrowe/turbo": "0.2.*"
19 | }
20 | }
21 | ```
22 |
23 | Update your packages with `composer update` or install with `composer install`.
24 |
25 | Providers
26 | ---------
27 |
28 | Providers enable instant usage of Turbo within different frameworks, we currently provide the following integrations:
29 |
30 | **Laravel**
31 |
32 | Add `Turbo\Provider\Laravel\TurboServiceProvider` to `app/config/app.php` and your good to go.
33 |
34 | The Laravel provider also registers a `turbo.pjax` event so that other parts of your app can listen for a pjax request. For example:
35 |
36 | ```php
37 | Event::listen('turbo.pjax', function($request, $response) {
38 | $response->header('X-App-Msg', 'Hello world');
39 | });
40 | ```
41 |
42 | **Fuelphp**
43 |
44 | Add `class_alias('Turbo\\Provider\\Fuel\\Response', 'Response')` to the bottom of `fuel\app\bootstrap.php` and your good to go.
45 |
46 | Turbo also registers a `turbo.pjax` event that you can listen for. For example:
47 |
48 | ```php
49 | Event::register('turbo.pjax', function() {
50 | echo 'This is a pjax request';
51 | });
52 | ```
53 |
54 | PJAX
55 | ----
56 |
57 | To make this all work Turbo needs [PJAX](https://github.com/defunkt/jquery-pjax) to get and set the response.
58 | Just like Turbolinks we respond with the whole body, not just a section of it. In order to support this, you need
59 | to setup PJAX to use the `
` tag. A simple example of this would be:
60 |
61 | ```js
62 | $(function() {
63 | $(document).pjax('.js-pjax', 'body');
64 | });
65 | ```
66 |
67 | License
68 | -------
69 |
70 | Turbo is released under the MIT public license.
71 |
--------------------------------------------------------------------------------
/src/Turbo/Provider/Fuel/Response.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | */
9 |
10 | namespace Turbo\Provider\Fuel;
11 |
12 | use Event;
13 | use Turbo\Turbo;
14 |
15 | /**
16 | * Brings the power of Turbo/PJAX to Fuel.
17 | */
18 | class Response extends \Fuel\Core\Response
19 | {
20 | /**
21 | * Get the content/body to return to browser.
22 | *
23 | * If the request is a pjax one, only the body is returned.
24 | *
25 | * @param string $value
26 | * @return string
27 | */
28 | public function body($value = false)
29 | {
30 | $value AND $this->body = $value;
31 |
32 | // Deal with pjax request
33 | $turbo = new Turbo;
34 |
35 | if ($turbo->isPjax()) {
36 | $this->body = $turbo->extract((string)$this->body);
37 | }
38 |
39 | // Fire event, then remove so that not called multiple times
40 | Event::trigger('turbo.pjax');
41 | Event::unregister('turbo.pjax');
42 |
43 | return parent::body($this->body);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Turbo/Provider/Laravel/TurboServiceProvider.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | */
9 |
10 | namespace Turbo\Provider\Laravel;
11 |
12 | use Illuminate\Support\ServiceProvider;
13 | use App;
14 | use Event;
15 | use Turbo\Turbo;
16 |
17 | /**
18 | * Brings the power of Turbo/PJAX to Laravel.
19 | */
20 | class TurboServiceProvider extends ServiceProvider
21 | {
22 | /**
23 | * Register the service provider.
24 | *
25 | * @return void
26 | */
27 | public function register()
28 | {
29 | App::after(function($request, $response) {
30 |
31 | $turbo = new Turbo;
32 |
33 | if ($turbo->isPjax()) {
34 |
35 | if (is_a($response, 'Illuminate\Http\Response')) {
36 |
37 | // Extract the body from the response
38 | $content = (string)$response->getOriginalContent();
39 | $body = $turbo->extract($content);
40 |
41 | // Set new response content
42 | $response->setContent($body);
43 | }
44 |
45 | // Fire that we are in a pjax request
46 | Event::fire('turbo.pjax', array($request, $response));
47 | }
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Turbo/Turbo.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | */
9 |
10 | namespace Turbo;
11 |
12 | /**
13 | * Returns the body of the HTML along with any title.
14 | *
15 | * Checks for a PJAX request and tailors the response.
16 | */
17 | class Turbo
18 | {
19 | /**
20 | * Create a new instance of Turbo.
21 | */
22 | public function __construct()
23 | {
24 | }
25 |
26 | /**
27 | * Is this request a PJAX request?
28 | */
29 | public function isPjax()
30 | {
31 | return (isset($_SERVER['HTTP_X_PJAX']) OR isset($_GET['_pjax']));
32 | }
33 |
34 | /**
35 | * If PJAX request, extract HTML body. Any problems we just sent back the original content.
36 | *
37 | * @param string $content Original content you want to extract.
38 | * @return string
39 | */
40 | public function extract($content)
41 | {
42 | // Send back the original content if we aren't supposed to be extracting
43 | if (!is_string($content) OR !$this->isPjax()) {
44 | return $content;
45 | }
46 |
47 | // We only process if we find a valid
48 | preg_match('/(?:]*>)(.*)<\/body>/isU', $content, $matches);
49 |
50 | // Did we find the body
51 | if (count($matches) !== 2) {
52 | return $content;
53 | }
54 |
55 | $body = $matches[1];
56 |
57 | // Does the page have a title
58 | preg_match('@([^<]+)@', $content, $matches);
59 |
60 | // Did we find the title
61 | $title = (count($matches) === 2) ? $matches[0] : '';
62 |
63 | // Set new content
64 | return $title.$body;
65 | }
66 | }
--------------------------------------------------------------------------------
/tests/TurboTests/TurboTest.php:
--------------------------------------------------------------------------------
1 | turbo = new Turbo;
13 | $this->setIsPjax();
14 | }
15 |
16 | public function tearDown()
17 | {
18 | $this->removeIsPjax();
19 | }
20 |
21 | public function testIsPjax()
22 | {
23 | $this->assertTrue($this->turbo->isPjax());
24 | $this->removeIsPjax();
25 | $this->assertFalse($this->turbo->isPjax());
26 |
27 | // Test different variables that effect isPjax
28 | $_SERVER['HTTP_X_PJAX'] = true;
29 | $this->assertTrue($this->turbo->isPjax());
30 | $this->removeIsPjax();
31 |
32 | $_GET['_pjax'] = true;
33 | $this->assertTrue($this->turbo->isPjax());
34 | $this->removeIsPjax();
35 | }
36 |
37 | public function testNotString()
38 | {
39 | foreach (array(null, 1234, new \stdClass, true) as $check) {
40 | $this->assertEquals($check, $this->turbo->extract($check));
41 | }
42 | }
43 |
44 | public function testNoBodyFound()
45 | {
46 | foreach (array('test', 'test', 'test') as $check) {
47 | $this->assertEquals($check, $this->turbo->extract($check));
48 | }
49 | }
50 |
51 | public function testBodyTagRemoved()
52 | {
53 | $str = 'This is just a test';
54 | $content = $this->turbo->extract(''.$str.'');
55 |
56 | $this->assertEquals($str, $content);
57 | }
58 |
59 | public function testNoTitleFound()
60 | {
61 | // opening tag
62 | $content = $this->turbo->extract('NoodleTest');
63 | $this->assertEquals('Test', $content);
64 |
65 | // closing tag
66 | $content = $this->turbo->extract('NoodleTest');
67 | $this->assertEquals('Test', $content);
68 | }
69 |
70 | public function testTitleFound()
71 | {
72 | $html = '';
73 | $html .= 'Hello world';
74 | $html .= 'Butter Bean';
75 | $html .= '';
76 |
77 | $this->assertEquals('Hello worldButter Bean', $this->turbo->extract($html));
78 | }
79 |
80 | public function testIsNotPjaxExtract()
81 | {
82 | $this->removeIsPjax();
83 | $str = 'test';
84 |
85 | $this->assertEquals($str, $this->turbo->extract($str));
86 | }
87 |
88 | public function setIsPjax()
89 | {
90 | $_SERVER['HTTP_X_PJAX'] = true;
91 | $_GET['_pjax'] = true;
92 | }
93 |
94 | public function removeIsPjax()
95 | {
96 | unset($_SERVER['HTTP_X_PJAX'], $_GET['_pjax']);
97 | }
98 | }
--------------------------------------------------------------------------------