├── .gitignore
├── .php_cs
├── .travis.yml
├── README.md
├── composer.json
├── composer.lock
├── examples
├── node-server
│ ├── package.json
│ └── server.js
├── php-server
│ ├── composer.json
│ ├── composer.lock
│ └── server.php
└── v8.php
├── phpunit.xml.dist
├── src
├── React.php
├── ReactFactory.php
├── Renderer
│ ├── FragmentProvidingRendererTrait.php
│ ├── HTTPServerRenderer.php
│ ├── LoggingRendererTrait.php
│ ├── NodeProcessRenderer.php
│ ├── NullRenderer.php
│ ├── RendererInterface.php
│ ├── SourceFilesRendererTrait.php
│ ├── StdInProcessRendererTrait.php
│ └── V8JsRenderer.php
└── RuntimeFragmentProvider
│ ├── GlobalObjectProvider.php
│ ├── ProviderInterface.php
│ └── SynchronousRequireProvider.php
└── tests
├── bootstrap.php
├── cases
└── Renderer
│ └── V8JsRendererTest.php
└── fixtures
├── TestComponent.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | /.idea/
3 | node_modules
4 | /tests/fixtures/bundle.js
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 | name('*.php')
5 | ->exclude(array(
6 | 'vendor'
7 | ))
8 | ->in(__DIR__);
9 |
10 | return Symfony\CS\Config\Config::create()
11 | ->finder($finder);
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.3
5 | - 5.4
6 | - 5.5
7 |
8 | before_script:
9 | - composer self-update
10 | - composer install --dev
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ReactJS PHP Render
2 |
3 | This library aims to provide multiple options for rendering React from PHP.
4 |
5 | ## Experimental
6 |
7 | The API is experimental and is likely to change.
8 |
9 | ## Concepts
10 |
11 | * Renderer (`ReactJS\Renderer\RendererInterface`)
12 | * This interface is implemented by mutiple renderers to provide different potential rendering options (HTTP Server, V8Js etc)
13 | * RuntimeFragmentProvider (`ReactJS\RuntimeFragmentProvider\ProviderInterface`)
14 | * This interface is implemented to provider different environment support (CommonJS, Globals etc)
15 |
16 | ## Usage
17 |
18 | Renderers can be used directly to generate either "mountable" React HTML (including checksums and ids), or to generate static markup.
19 |
20 | The React class (`ReactJS\React`) can be used to generate mountable React HTML along with JavaScript that will automatically mount the browser React component into the generated server rendered markup.
21 |
22 | ### Node
23 |
24 | When using a node process, users are required to provide source file(s) in an appropriate format for node to execute, these source file(s) need include:
25 |
26 | * React
27 | * The component you are attempting to render
28 |
29 | ```php
30 | $node = ReactJS\ReactFactory::createUsingNode(
31 | '/usr/bin/nodejs',
32 | ['bundle.js'] // bundle.js is a browserified bundle with React and TestComponent
33 | );
34 |
35 | echo $node->renderAutoMountingComponent('./TestComponent');
36 | ```
37 |
38 | ### V8
39 |
40 | When using the V8Js php extension, users are required to provide source file(s) in the appropriate format for V8 to execute, these source file(s) need include:
41 |
42 | * React
43 | * The component you are attempting to render
44 |
45 | ```php
46 | $v8 = ReactJS\ReactFactory::createUsingV8(
47 | ['bundle.js'] // bundle.js is a browserified bundle with React and TestComponent
48 | );
49 |
50 | echo $v8->renderAutoMountingComponent('./TestComponent');
51 | ```
52 |
53 | The result:
54 |
55 | ```html
56 |
57 | Some testing content
58 |
59 |
65 | ```
66 |
67 | ## Installation (with composer)
68 |
69 | $ composer require camspiers/reactjs-php-render:dev-master
70 |
71 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "camspiers/reactjs-php-render",
3 | "description": "React rendering from PHP",
4 | "authors": [
5 | {
6 | "name": "Cam Spiers",
7 | "email": "camspiers@gmail.com"
8 | },
9 | {
10 | "name": "Pieter Vanderwerff",
11 | "email": "me@pieter.io"
12 | }
13 | ],
14 | "autoload": {
15 | "psr-4": {
16 | "ReactJS\\": "src/"
17 | }
18 | },
19 | "require-dev": {
20 | "phpunit/phpunit": "~4.0"
21 | },
22 | "require": {
23 | "php": ">=5.4.0",
24 | "psr/log": "~1.0",
25 | "guzzlehttp/guzzle": "~4.0",
26 | "symfony/process": "~2.5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "426bffde737d8ada797a614bc4cad5f1",
8 | "packages": [
9 | {
10 | "name": "guzzlehttp/guzzle",
11 | "version": "4.1.1",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/guzzle/guzzle.git",
15 | "reference": "577a69ff7d0a24e9576a2885c3a7afbaadd51ec1"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/577a69ff7d0a24e9576a2885c3a7afbaadd51ec1",
20 | "reference": "577a69ff7d0a24e9576a2885c3a7afbaadd51ec1",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "ext-json": "*",
25 | "guzzlehttp/streams": "~1.0",
26 | "php": ">=5.4.0"
27 | },
28 | "require-dev": {
29 | "ext-curl": "*",
30 | "phpunit/phpunit": "~4.0",
31 | "psr/log": "~1.0"
32 | },
33 | "suggest": {
34 | "ext-curl": "Guzzle will use specific adapters if cURL is present"
35 | },
36 | "type": "library",
37 | "extra": {
38 | "branch-alias": {
39 | "dev-master": "4.1.x-dev"
40 | }
41 | },
42 | "autoload": {
43 | "psr-4": {
44 | "GuzzleHttp\\": "src/"
45 | },
46 | "files": [
47 | "src/functions.php"
48 | ]
49 | },
50 | "notification-url": "https://packagist.org/downloads/",
51 | "license": [
52 | "MIT"
53 | ],
54 | "authors": [
55 | {
56 | "name": "Michael Dowling",
57 | "email": "mtdowling@gmail.com",
58 | "homepage": "https://github.com/mtdowling"
59 | }
60 | ],
61 | "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
62 | "homepage": "http://guzzlephp.org/",
63 | "keywords": [
64 | "client",
65 | "curl",
66 | "framework",
67 | "http",
68 | "http client",
69 | "rest",
70 | "web service"
71 | ],
72 | "time": "2014-06-08 20:00:20"
73 | },
74 | {
75 | "name": "guzzlehttp/streams",
76 | "version": "1.1.0",
77 | "source": {
78 | "type": "git",
79 | "url": "https://github.com/guzzle/streams.git",
80 | "reference": "cf0c8c33ca95cc147efba4c714f630ee44767180"
81 | },
82 | "dist": {
83 | "type": "zip",
84 | "url": "https://api.github.com/repos/guzzle/streams/zipball/cf0c8c33ca95cc147efba4c714f630ee44767180",
85 | "reference": "cf0c8c33ca95cc147efba4c714f630ee44767180",
86 | "shasum": ""
87 | },
88 | "require": {
89 | "php": ">=5.4.0"
90 | },
91 | "require-dev": {
92 | "phpunit/phpunit": "~4.0"
93 | },
94 | "type": "library",
95 | "extra": {
96 | "branch-alias": {
97 | "dev-master": "1.0.x-dev"
98 | }
99 | },
100 | "autoload": {
101 | "psr-4": {
102 | "GuzzleHttp\\Stream\\": "src/"
103 | },
104 | "files": [
105 | "src/functions.php"
106 | ]
107 | },
108 | "notification-url": "https://packagist.org/downloads/",
109 | "license": [
110 | "MIT"
111 | ],
112 | "authors": [
113 | {
114 | "name": "Michael Dowling",
115 | "email": "mtdowling@gmail.com",
116 | "homepage": "https://github.com/mtdowling"
117 | }
118 | ],
119 | "description": "Provides a simple abstraction over streams of data (Guzzle 4+)",
120 | "homepage": "http://guzzlephp.org/",
121 | "keywords": [
122 | "Guzzle",
123 | "stream"
124 | ],
125 | "time": "2014-04-03 04:48:24"
126 | },
127 | {
128 | "name": "psr/log",
129 | "version": "1.0.0",
130 | "source": {
131 | "type": "git",
132 | "url": "https://github.com/php-fig/log.git",
133 | "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
134 | },
135 | "dist": {
136 | "type": "zip",
137 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
138 | "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
139 | "shasum": ""
140 | },
141 | "type": "library",
142 | "autoload": {
143 | "psr-0": {
144 | "Psr\\Log\\": ""
145 | }
146 | },
147 | "notification-url": "https://packagist.org/downloads/",
148 | "license": [
149 | "MIT"
150 | ],
151 | "authors": [
152 | {
153 | "name": "PHP-FIG",
154 | "homepage": "http://www.php-fig.org/"
155 | }
156 | ],
157 | "description": "Common interface for logging libraries",
158 | "keywords": [
159 | "log",
160 | "psr",
161 | "psr-3"
162 | ],
163 | "time": "2012-12-21 11:40:51"
164 | },
165 | {
166 | "name": "symfony/process",
167 | "version": "v2.5.0",
168 | "target-dir": "Symfony/Component/Process",
169 | "source": {
170 | "type": "git",
171 | "url": "https://github.com/symfony/Process.git",
172 | "reference": "5d7d78e23894544740219e006320678cfa4cd45b"
173 | },
174 | "dist": {
175 | "type": "zip",
176 | "url": "https://api.github.com/repos/symfony/Process/zipball/5d7d78e23894544740219e006320678cfa4cd45b",
177 | "reference": "5d7d78e23894544740219e006320678cfa4cd45b",
178 | "shasum": ""
179 | },
180 | "require": {
181 | "php": ">=5.3.3"
182 | },
183 | "type": "library",
184 | "extra": {
185 | "branch-alias": {
186 | "dev-master": "2.5-dev"
187 | }
188 | },
189 | "autoload": {
190 | "psr-0": {
191 | "Symfony\\Component\\Process\\": ""
192 | }
193 | },
194 | "notification-url": "https://packagist.org/downloads/",
195 | "license": [
196 | "MIT"
197 | ],
198 | "authors": [
199 | {
200 | "name": "Fabien Potencier",
201 | "email": "fabien@symfony.com",
202 | "homepage": "http://fabien.potencier.org",
203 | "role": "Lead Developer"
204 | },
205 | {
206 | "name": "Symfony Community",
207 | "homepage": "http://symfony.com/contributors"
208 | }
209 | ],
210 | "description": "Symfony Process Component",
211 | "homepage": "http://symfony.com",
212 | "time": "2014-05-23 09:02:52"
213 | }
214 | ],
215 | "packages-dev": [
216 | {
217 | "name": "phpunit/php-code-coverage",
218 | "version": "2.0.8",
219 | "source": {
220 | "type": "git",
221 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
222 | "reference": "58401826c8cfc8fd689b60026e91c337df374bca"
223 | },
224 | "dist": {
225 | "type": "zip",
226 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/58401826c8cfc8fd689b60026e91c337df374bca",
227 | "reference": "58401826c8cfc8fd689b60026e91c337df374bca",
228 | "shasum": ""
229 | },
230 | "require": {
231 | "php": ">=5.3.3",
232 | "phpunit/php-file-iterator": "~1.3.1",
233 | "phpunit/php-text-template": "~1.2.0",
234 | "phpunit/php-token-stream": "~1.2.2",
235 | "sebastian/environment": "~1.0.0",
236 | "sebastian/version": "~1.0.3"
237 | },
238 | "require-dev": {
239 | "ext-xdebug": ">=2.1.4",
240 | "phpunit/phpunit": "~4.0.14"
241 | },
242 | "suggest": {
243 | "ext-dom": "*",
244 | "ext-xdebug": ">=2.2.1",
245 | "ext-xmlwriter": "*"
246 | },
247 | "type": "library",
248 | "extra": {
249 | "branch-alias": {
250 | "dev-master": "2.0.x-dev"
251 | }
252 | },
253 | "autoload": {
254 | "classmap": [
255 | "src/"
256 | ]
257 | },
258 | "notification-url": "https://packagist.org/downloads/",
259 | "include-path": [
260 | ""
261 | ],
262 | "license": [
263 | "BSD-3-Clause"
264 | ],
265 | "authors": [
266 | {
267 | "name": "Sebastian Bergmann",
268 | "email": "sb@sebastian-bergmann.de",
269 | "role": "lead"
270 | }
271 | ],
272 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
273 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
274 | "keywords": [
275 | "coverage",
276 | "testing",
277 | "xunit"
278 | ],
279 | "time": "2014-05-26 14:55:24"
280 | },
281 | {
282 | "name": "phpunit/php-file-iterator",
283 | "version": "1.3.4",
284 | "source": {
285 | "type": "git",
286 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
287 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
288 | },
289 | "dist": {
290 | "type": "zip",
291 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
292 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
293 | "shasum": ""
294 | },
295 | "require": {
296 | "php": ">=5.3.3"
297 | },
298 | "type": "library",
299 | "autoload": {
300 | "classmap": [
301 | "File/"
302 | ]
303 | },
304 | "notification-url": "https://packagist.org/downloads/",
305 | "include-path": [
306 | ""
307 | ],
308 | "license": [
309 | "BSD-3-Clause"
310 | ],
311 | "authors": [
312 | {
313 | "name": "Sebastian Bergmann",
314 | "email": "sb@sebastian-bergmann.de",
315 | "role": "lead"
316 | }
317 | ],
318 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
319 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
320 | "keywords": [
321 | "filesystem",
322 | "iterator"
323 | ],
324 | "time": "2013-10-10 15:34:57"
325 | },
326 | {
327 | "name": "phpunit/php-text-template",
328 | "version": "1.2.0",
329 | "source": {
330 | "type": "git",
331 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
332 | "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
333 | },
334 | "dist": {
335 | "type": "zip",
336 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
337 | "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
338 | "shasum": ""
339 | },
340 | "require": {
341 | "php": ">=5.3.3"
342 | },
343 | "type": "library",
344 | "autoload": {
345 | "classmap": [
346 | "Text/"
347 | ]
348 | },
349 | "notification-url": "https://packagist.org/downloads/",
350 | "include-path": [
351 | ""
352 | ],
353 | "license": [
354 | "BSD-3-Clause"
355 | ],
356 | "authors": [
357 | {
358 | "name": "Sebastian Bergmann",
359 | "email": "sb@sebastian-bergmann.de",
360 | "role": "lead"
361 | }
362 | ],
363 | "description": "Simple template engine.",
364 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
365 | "keywords": [
366 | "template"
367 | ],
368 | "time": "2014-01-30 17:20:04"
369 | },
370 | {
371 | "name": "phpunit/php-timer",
372 | "version": "1.0.5",
373 | "source": {
374 | "type": "git",
375 | "url": "https://github.com/sebastianbergmann/php-timer.git",
376 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
377 | },
378 | "dist": {
379 | "type": "zip",
380 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
381 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
382 | "shasum": ""
383 | },
384 | "require": {
385 | "php": ">=5.3.3"
386 | },
387 | "type": "library",
388 | "autoload": {
389 | "classmap": [
390 | "PHP/"
391 | ]
392 | },
393 | "notification-url": "https://packagist.org/downloads/",
394 | "include-path": [
395 | ""
396 | ],
397 | "license": [
398 | "BSD-3-Clause"
399 | ],
400 | "authors": [
401 | {
402 | "name": "Sebastian Bergmann",
403 | "email": "sb@sebastian-bergmann.de",
404 | "role": "lead"
405 | }
406 | ],
407 | "description": "Utility class for timing",
408 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
409 | "keywords": [
410 | "timer"
411 | ],
412 | "time": "2013-08-02 07:42:54"
413 | },
414 | {
415 | "name": "phpunit/php-token-stream",
416 | "version": "1.2.2",
417 | "source": {
418 | "type": "git",
419 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
420 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32"
421 | },
422 | "dist": {
423 | "type": "zip",
424 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32",
425 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32",
426 | "shasum": ""
427 | },
428 | "require": {
429 | "ext-tokenizer": "*",
430 | "php": ">=5.3.3"
431 | },
432 | "type": "library",
433 | "extra": {
434 | "branch-alias": {
435 | "dev-master": "1.2-dev"
436 | }
437 | },
438 | "autoload": {
439 | "classmap": [
440 | "PHP/"
441 | ]
442 | },
443 | "notification-url": "https://packagist.org/downloads/",
444 | "include-path": [
445 | ""
446 | ],
447 | "license": [
448 | "BSD-3-Clause"
449 | ],
450 | "authors": [
451 | {
452 | "name": "Sebastian Bergmann",
453 | "email": "sb@sebastian-bergmann.de",
454 | "role": "lead"
455 | }
456 | ],
457 | "description": "Wrapper around PHP's tokenizer extension.",
458 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
459 | "keywords": [
460 | "tokenizer"
461 | ],
462 | "time": "2014-03-03 05:10:30"
463 | },
464 | {
465 | "name": "phpunit/phpunit",
466 | "version": "4.1.3",
467 | "source": {
468 | "type": "git",
469 | "url": "https://github.com/sebastianbergmann/phpunit.git",
470 | "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91"
471 | },
472 | "dist": {
473 | "type": "zip",
474 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/939cb801b3b2aa253aedd0b279f40bb8f35cec91",
475 | "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91",
476 | "shasum": ""
477 | },
478 | "require": {
479 | "ext-dom": "*",
480 | "ext-json": "*",
481 | "ext-pcre": "*",
482 | "ext-reflection": "*",
483 | "ext-spl": "*",
484 | "php": ">=5.3.3",
485 | "phpunit/php-code-coverage": "~2.0",
486 | "phpunit/php-file-iterator": "~1.3.1",
487 | "phpunit/php-text-template": "~1.2",
488 | "phpunit/php-timer": "~1.0.2",
489 | "phpunit/phpunit-mock-objects": "~2.1",
490 | "sebastian/comparator": "~1.0",
491 | "sebastian/diff": "~1.1",
492 | "sebastian/environment": "~1.0",
493 | "sebastian/exporter": "~1.0",
494 | "sebastian/version": "~1.0",
495 | "symfony/yaml": "~2.0"
496 | },
497 | "suggest": {
498 | "phpunit/php-invoker": "~1.1"
499 | },
500 | "bin": [
501 | "phpunit"
502 | ],
503 | "type": "library",
504 | "extra": {
505 | "branch-alias": {
506 | "dev-master": "4.1.x-dev"
507 | }
508 | },
509 | "autoload": {
510 | "classmap": [
511 | "src/"
512 | ]
513 | },
514 | "notification-url": "https://packagist.org/downloads/",
515 | "include-path": [
516 | "",
517 | "../../symfony/yaml/"
518 | ],
519 | "license": [
520 | "BSD-3-Clause"
521 | ],
522 | "authors": [
523 | {
524 | "name": "Sebastian Bergmann",
525 | "email": "sebastian@phpunit.de",
526 | "role": "lead"
527 | }
528 | ],
529 | "description": "The PHP Unit Testing framework.",
530 | "homepage": "http://www.phpunit.de/",
531 | "keywords": [
532 | "phpunit",
533 | "testing",
534 | "xunit"
535 | ],
536 | "time": "2014-06-11 14:15:47"
537 | },
538 | {
539 | "name": "phpunit/phpunit-mock-objects",
540 | "version": "2.1.4",
541 | "source": {
542 | "type": "git",
543 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
544 | "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f"
545 | },
546 | "dist": {
547 | "type": "zip",
548 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f",
549 | "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f",
550 | "shasum": ""
551 | },
552 | "require": {
553 | "php": ">=5.3.3",
554 | "phpunit/php-text-template": "~1.2"
555 | },
556 | "require-dev": {
557 | "phpunit/phpunit": "~4.1"
558 | },
559 | "suggest": {
560 | "ext-soap": "*"
561 | },
562 | "type": "library",
563 | "extra": {
564 | "branch-alias": {
565 | "dev-master": "2.1.x-dev"
566 | }
567 | },
568 | "autoload": {
569 | "classmap": [
570 | "src/"
571 | ]
572 | },
573 | "notification-url": "https://packagist.org/downloads/",
574 | "include-path": [
575 | ""
576 | ],
577 | "license": [
578 | "BSD-3-Clause"
579 | ],
580 | "authors": [
581 | {
582 | "name": "Sebastian Bergmann",
583 | "email": "sb@sebastian-bergmann.de",
584 | "role": "lead"
585 | }
586 | ],
587 | "description": "Mock Object library for PHPUnit",
588 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
589 | "keywords": [
590 | "mock",
591 | "xunit"
592 | ],
593 | "time": "2014-06-07 16:22:57"
594 | },
595 | {
596 | "name": "sebastian/comparator",
597 | "version": "1.0.0",
598 | "source": {
599 | "type": "git",
600 | "url": "https://github.com/sebastianbergmann/comparator.git",
601 | "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2"
602 | },
603 | "dist": {
604 | "type": "zip",
605 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2",
606 | "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2",
607 | "shasum": ""
608 | },
609 | "require": {
610 | "php": ">=5.3.3",
611 | "sebastian/diff": "~1.1",
612 | "sebastian/exporter": "~1.0"
613 | },
614 | "require-dev": {
615 | "phpunit/phpunit": "~4.1"
616 | },
617 | "type": "library",
618 | "extra": {
619 | "branch-alias": {
620 | "dev-master": "1.0.x-dev"
621 | }
622 | },
623 | "autoload": {
624 | "classmap": [
625 | "src/"
626 | ]
627 | },
628 | "notification-url": "https://packagist.org/downloads/",
629 | "license": [
630 | "BSD-3-Clause"
631 | ],
632 | "authors": [
633 | {
634 | "name": "Sebastian Bergmann",
635 | "email": "sebastian@phpunit.de",
636 | "role": "lead"
637 | },
638 | {
639 | "name": "Jeff Welch",
640 | "email": "whatthejeff@gmail.com"
641 | },
642 | {
643 | "name": "Volker Dusch",
644 | "email": "github@wallbash.com"
645 | },
646 | {
647 | "name": "Bernhard Schussek",
648 | "email": "bschussek@2bepublished.at"
649 | }
650 | ],
651 | "description": "Provides the functionality to compare PHP values for equality",
652 | "homepage": "http://www.github.com/sebastianbergmann/comparator",
653 | "keywords": [
654 | "comparator",
655 | "compare",
656 | "equality"
657 | ],
658 | "time": "2014-05-02 07:05:58"
659 | },
660 | {
661 | "name": "sebastian/diff",
662 | "version": "1.1.0",
663 | "source": {
664 | "type": "git",
665 | "url": "https://github.com/sebastianbergmann/diff.git",
666 | "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d"
667 | },
668 | "dist": {
669 | "type": "zip",
670 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d",
671 | "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d",
672 | "shasum": ""
673 | },
674 | "require": {
675 | "php": ">=5.3.3"
676 | },
677 | "type": "library",
678 | "extra": {
679 | "branch-alias": {
680 | "dev-master": "1.1-dev"
681 | }
682 | },
683 | "autoload": {
684 | "classmap": [
685 | "src/"
686 | ]
687 | },
688 | "notification-url": "https://packagist.org/downloads/",
689 | "license": [
690 | "BSD-3-Clause"
691 | ],
692 | "authors": [
693 | {
694 | "name": "Sebastian Bergmann",
695 | "email": "sebastian@phpunit.de",
696 | "role": "lead"
697 | },
698 | {
699 | "name": "Kore Nordmann",
700 | "email": "mail@kore-nordmann.de"
701 | }
702 | ],
703 | "description": "Diff implementation",
704 | "homepage": "http://www.github.com/sebastianbergmann/diff",
705 | "keywords": [
706 | "diff"
707 | ],
708 | "time": "2013-08-03 16:46:33"
709 | },
710 | {
711 | "name": "sebastian/environment",
712 | "version": "1.0.0",
713 | "source": {
714 | "type": "git",
715 | "url": "https://github.com/sebastianbergmann/environment.git",
716 | "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a"
717 | },
718 | "dist": {
719 | "type": "zip",
720 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/79517609ec01139cd7e9fded0dd7ce08c952ef6a",
721 | "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a",
722 | "shasum": ""
723 | },
724 | "require": {
725 | "php": ">=5.3.3"
726 | },
727 | "require-dev": {
728 | "phpunit/phpunit": "4.0.*@dev"
729 | },
730 | "type": "library",
731 | "extra": {
732 | "branch-alias": {
733 | "dev-master": "1.0.x-dev"
734 | }
735 | },
736 | "autoload": {
737 | "classmap": [
738 | "src/"
739 | ]
740 | },
741 | "notification-url": "https://packagist.org/downloads/",
742 | "license": [
743 | "BSD-3-Clause"
744 | ],
745 | "authors": [
746 | {
747 | "name": "Sebastian Bergmann",
748 | "email": "sebastian@phpunit.de",
749 | "role": "lead"
750 | }
751 | ],
752 | "description": "Provides functionality to handle HHVM/PHP environments",
753 | "homepage": "http://www.github.com/sebastianbergmann/environment",
754 | "keywords": [
755 | "Xdebug",
756 | "environment",
757 | "hhvm"
758 | ],
759 | "time": "2014-02-18 16:17:19"
760 | },
761 | {
762 | "name": "sebastian/exporter",
763 | "version": "1.0.1",
764 | "source": {
765 | "type": "git",
766 | "url": "https://github.com/sebastianbergmann/exporter.git",
767 | "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529"
768 | },
769 | "dist": {
770 | "type": "zip",
771 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529",
772 | "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529",
773 | "shasum": ""
774 | },
775 | "require": {
776 | "php": ">=5.3.3"
777 | },
778 | "require-dev": {
779 | "phpunit/phpunit": "4.0.*@dev"
780 | },
781 | "type": "library",
782 | "extra": {
783 | "branch-alias": {
784 | "dev-master": "1.0.x-dev"
785 | }
786 | },
787 | "autoload": {
788 | "classmap": [
789 | "src/"
790 | ]
791 | },
792 | "notification-url": "https://packagist.org/downloads/",
793 | "license": [
794 | "BSD-3-Clause"
795 | ],
796 | "authors": [
797 | {
798 | "name": "Sebastian Bergmann",
799 | "email": "sebastian@phpunit.de",
800 | "role": "lead"
801 | },
802 | {
803 | "name": "Jeff Welch",
804 | "email": "whatthejeff@gmail.com"
805 | },
806 | {
807 | "name": "Volker Dusch",
808 | "email": "github@wallbash.com"
809 | },
810 | {
811 | "name": "Adam Harvey",
812 | "email": "aharvey@php.net",
813 | "role": "Lead"
814 | },
815 | {
816 | "name": "Bernhard Schussek",
817 | "email": "bschussek@2bepublished.at"
818 | }
819 | ],
820 | "description": "Provides the functionality to export PHP variables for visualization",
821 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
822 | "keywords": [
823 | "export",
824 | "exporter"
825 | ],
826 | "time": "2014-02-16 08:26:31"
827 | },
828 | {
829 | "name": "sebastian/version",
830 | "version": "1.0.3",
831 | "source": {
832 | "type": "git",
833 | "url": "https://github.com/sebastianbergmann/version.git",
834 | "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43"
835 | },
836 | "dist": {
837 | "type": "zip",
838 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
839 | "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
840 | "shasum": ""
841 | },
842 | "type": "library",
843 | "autoload": {
844 | "classmap": [
845 | "src/"
846 | ]
847 | },
848 | "notification-url": "https://packagist.org/downloads/",
849 | "license": [
850 | "BSD-3-Clause"
851 | ],
852 | "authors": [
853 | {
854 | "name": "Sebastian Bergmann",
855 | "email": "sebastian@phpunit.de",
856 | "role": "lead"
857 | }
858 | ],
859 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
860 | "homepage": "https://github.com/sebastianbergmann/version",
861 | "time": "2014-03-07 15:35:33"
862 | },
863 | {
864 | "name": "symfony/yaml",
865 | "version": "v2.5.0",
866 | "target-dir": "Symfony/Component/Yaml",
867 | "source": {
868 | "type": "git",
869 | "url": "https://github.com/symfony/Yaml.git",
870 | "reference": "b4b09c68ec2f2727574544ef0173684281a5033c"
871 | },
872 | "dist": {
873 | "type": "zip",
874 | "url": "https://api.github.com/repos/symfony/Yaml/zipball/b4b09c68ec2f2727574544ef0173684281a5033c",
875 | "reference": "b4b09c68ec2f2727574544ef0173684281a5033c",
876 | "shasum": ""
877 | },
878 | "require": {
879 | "php": ">=5.3.3"
880 | },
881 | "type": "library",
882 | "extra": {
883 | "branch-alias": {
884 | "dev-master": "2.5-dev"
885 | }
886 | },
887 | "autoload": {
888 | "psr-0": {
889 | "Symfony\\Component\\Yaml\\": ""
890 | }
891 | },
892 | "notification-url": "https://packagist.org/downloads/",
893 | "license": [
894 | "MIT"
895 | ],
896 | "authors": [
897 | {
898 | "name": "Fabien Potencier",
899 | "email": "fabien@symfony.com",
900 | "homepage": "http://fabien.potencier.org",
901 | "role": "Lead Developer"
902 | },
903 | {
904 | "name": "Symfony Community",
905 | "homepage": "http://symfony.com/contributors"
906 | }
907 | ],
908 | "description": "Symfony Yaml Component",
909 | "homepage": "http://symfony.com",
910 | "time": "2014-05-16 14:25:18"
911 | }
912 | ],
913 | "aliases": [],
914 | "minimum-stability": "stable",
915 | "stability-flags": [],
916 | "platform": {
917 | "php": ">=5.4.0"
918 | },
919 | "platform-dev": []
920 | }
921 |
--------------------------------------------------------------------------------
/examples/node-server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-node-server",
3 | "version": "0.0.0",
4 | "description": "",
5 | "author": "Cam Spiers",
6 | "main": "server.js",
7 | "scripts": {
8 | "start": "node server.js"
9 | },
10 | "dependencies": {
11 | "react": "0.10.0",
12 | "express": "3.5.1",
13 | "node-jsx": "0.10.0"
14 | }
15 | }
--------------------------------------------------------------------------------
/examples/node-server/server.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var express = require('express');
3 | var path = require('path');
4 | var app = express();
5 |
6 | require('node-jsx').install();
7 | app.use(express.urlencoded());
8 |
9 | function validateRequest(data) {
10 | var errors = [];
11 |
12 | if (!data['renderType']) {
13 | errors.push('renderType empty');
14 | } else if (['mountable', 'static'].indexOf(data['renderType']) < 0) {
15 | errors.push('Invalid renderType');
16 | }
17 |
18 | if (!data['componentPath']) {
19 | errors.push('componentPath empty');
20 | }
21 |
22 | if (!data['props']) {
23 | errors.push('props empty');
24 | }
25 |
26 | return errors;
27 | }
28 |
29 | app.post('/', function(req, res){
30 | var errors = validateRequest(req.body);
31 |
32 | if (errors.length) {
33 | res.send(errors);
34 | return;
35 | }
36 |
37 | var reactFunction;
38 |
39 | if (req.body['renderType'] === 'static') {
40 | reactFunction = 'renderComponentToStaticMarkup';
41 | } else {
42 | reactFunction = 'renderComponentToString';
43 | }
44 |
45 | var component = require(path.resolve(req.body['componentPath']));
46 | var props = JSON.parse(req.body['props'] || '{}');
47 |
48 | res.send(React[reactFunction](component(props)));
49 | });
50 |
--------------------------------------------------------------------------------
/examples/php-server/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": {
3 | "react/http": "~0.4",
4 | "docopt/docopt": "~0.6"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/php-server/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "4c7a7eac28748974dced21d89316a37b",
8 | "packages": [
9 | {
10 | "name": "docopt/docopt",
11 | "version": "0.6.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/docopt/docopt.php.git",
15 | "reference": "ad2afba96771ab5d8c29c36d720461886b338d78"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/docopt/docopt.php/zipball/ad2afba96771ab5d8c29c36d720461886b338d78",
20 | "reference": "ad2afba96771ab5d8c29c36d720461886b338d78",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": ">=5.3.0"
25 | },
26 | "type": "library",
27 | "autoload": {
28 | "classmap": [
29 | "src/docopt.php"
30 | ]
31 | },
32 | "notification-url": "https://packagist.org/downloads/",
33 | "license": [
34 | "MIT"
35 | ],
36 | "authors": [
37 | {
38 | "name": "Blake Williams",
39 | "email": "code@shabbyrobe.org",
40 | "homepage": "http://docopt.org/",
41 | "role": "Developer"
42 | }
43 | ],
44 | "description": "Port of Python's docopt for PHP 5.3",
45 | "homepage": "http://github.com/docopt/docopt.php",
46 | "keywords": [
47 | "cli",
48 | "docs"
49 | ],
50 | "time": "2013-01-24 10:17:13"
51 | },
52 | {
53 | "name": "evenement/evenement",
54 | "version": "v2.0.0",
55 | "source": {
56 | "type": "git",
57 | "url": "https://github.com/igorw/evenement.git",
58 | "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e"
59 | },
60 | "dist": {
61 | "type": "zip",
62 | "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e",
63 | "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e",
64 | "shasum": ""
65 | },
66 | "require": {
67 | "php": ">=5.4.0"
68 | },
69 | "type": "library",
70 | "extra": {
71 | "branch-alias": {
72 | "dev-master": "2.0-dev"
73 | }
74 | },
75 | "autoload": {
76 | "psr-0": {
77 | "Evenement": "src"
78 | }
79 | },
80 | "notification-url": "https://packagist.org/downloads/",
81 | "license": [
82 | "MIT"
83 | ],
84 | "authors": [
85 | {
86 | "name": "Igor Wiedler",
87 | "email": "igor@wiedler.ch",
88 | "homepage": "http://wiedler.ch/igor/"
89 | }
90 | ],
91 | "description": "Événement is a very simple event dispatching library for PHP",
92 | "keywords": [
93 | "event-dispatcher",
94 | "event-emitter"
95 | ],
96 | "time": "2012-11-02 14:49:47"
97 | },
98 | {
99 | "name": "guzzle/parser",
100 | "version": "v3.9.1",
101 | "target-dir": "Guzzle/Parser",
102 | "source": {
103 | "type": "git",
104 | "url": "https://github.com/guzzle/parser.git",
105 | "reference": "6874d171318a8e93eb6d224cf85e4678490b625c"
106 | },
107 | "dist": {
108 | "type": "zip",
109 | "url": "https://api.github.com/repos/guzzle/parser/zipball/6874d171318a8e93eb6d224cf85e4678490b625c",
110 | "reference": "6874d171318a8e93eb6d224cf85e4678490b625c",
111 | "shasum": ""
112 | },
113 | "require": {
114 | "php": ">=5.3.2"
115 | },
116 | "type": "library",
117 | "extra": {
118 | "branch-alias": {
119 | "dev-master": "3.7-dev"
120 | }
121 | },
122 | "autoload": {
123 | "psr-0": {
124 | "Guzzle\\Parser": ""
125 | }
126 | },
127 | "notification-url": "https://packagist.org/downloads/",
128 | "license": [
129 | "MIT"
130 | ],
131 | "description": "Interchangeable parsers used by Guzzle",
132 | "homepage": "http://guzzlephp.org/",
133 | "keywords": [
134 | "URI Template",
135 | "cookie",
136 | "http",
137 | "message",
138 | "url"
139 | ],
140 | "time": "2014-02-05 18:29:46"
141 | },
142 | {
143 | "name": "react/event-loop",
144 | "version": "v0.4.1",
145 | "source": {
146 | "type": "git",
147 | "url": "https://github.com/reactphp/event-loop.git",
148 | "reference": "18c5297087ca01de85518e2b55078f444144aa1b"
149 | },
150 | "dist": {
151 | "type": "zip",
152 | "url": "https://api.github.com/repos/reactphp/event-loop/zipball/18c5297087ca01de85518e2b55078f444144aa1b",
153 | "reference": "18c5297087ca01de85518e2b55078f444144aa1b",
154 | "shasum": ""
155 | },
156 | "require": {
157 | "php": ">=5.4.0"
158 | },
159 | "suggest": {
160 | "ext-event": "~1.0",
161 | "ext-libev": "*",
162 | "ext-libevent": ">=0.1.0"
163 | },
164 | "type": "library",
165 | "extra": {
166 | "branch-alias": {
167 | "dev-master": "0.4-dev"
168 | }
169 | },
170 | "autoload": {
171 | "psr-4": {
172 | "React\\EventLoop\\": ""
173 | }
174 | },
175 | "notification-url": "https://packagist.org/downloads/",
176 | "license": [
177 | "MIT"
178 | ],
179 | "description": "Event loop abstraction layer that libraries can use for evented I/O.",
180 | "keywords": [
181 | "event-loop"
182 | ],
183 | "time": "2014-02-26 17:36:58"
184 | },
185 | {
186 | "name": "react/http",
187 | "version": "v0.4.0",
188 | "source": {
189 | "type": "git",
190 | "url": "https://github.com/reactphp/http.git",
191 | "reference": "7b9d293b7a3f73acd840a341497e267d8562d637"
192 | },
193 | "dist": {
194 | "type": "zip",
195 | "url": "https://api.github.com/repos/reactphp/http/zipball/7b9d293b7a3f73acd840a341497e267d8562d637",
196 | "reference": "7b9d293b7a3f73acd840a341497e267d8562d637",
197 | "shasum": ""
198 | },
199 | "require": {
200 | "guzzle/parser": "~3.0",
201 | "php": ">=5.4.0",
202 | "react/socket": "0.4.*"
203 | },
204 | "type": "library",
205 | "extra": {
206 | "branch-alias": {
207 | "dev-master": "0.4-dev"
208 | }
209 | },
210 | "autoload": {
211 | "psr-4": {
212 | "React\\Http\\": ""
213 | }
214 | },
215 | "notification-url": "https://packagist.org/downloads/",
216 | "license": [
217 | "MIT"
218 | ],
219 | "description": "Library for building an evented http server.",
220 | "keywords": [
221 | "http"
222 | ],
223 | "time": "2014-02-02 01:11:26"
224 | },
225 | {
226 | "name": "react/socket",
227 | "version": "v0.4.2",
228 | "source": {
229 | "type": "git",
230 | "url": "https://github.com/reactphp/socket.git",
231 | "reference": "a6acf405ca53fc6cfbfe7c77778ededff46aa7cc"
232 | },
233 | "dist": {
234 | "type": "zip",
235 | "url": "https://api.github.com/repos/reactphp/socket/zipball/a6acf405ca53fc6cfbfe7c77778ededff46aa7cc",
236 | "reference": "a6acf405ca53fc6cfbfe7c77778ededff46aa7cc",
237 | "shasum": ""
238 | },
239 | "require": {
240 | "evenement/evenement": "~2.0",
241 | "php": ">=5.4.0",
242 | "react/event-loop": "0.4.*",
243 | "react/stream": "0.4.*"
244 | },
245 | "type": "library",
246 | "extra": {
247 | "branch-alias": {
248 | "dev-master": "0.4-dev"
249 | }
250 | },
251 | "autoload": {
252 | "psr-4": {
253 | "React\\Socket\\": "src"
254 | }
255 | },
256 | "notification-url": "https://packagist.org/downloads/",
257 | "license": [
258 | "MIT"
259 | ],
260 | "description": "Library for building an evented socket server.",
261 | "keywords": [
262 | "Socket"
263 | ],
264 | "time": "2014-05-25 17:02:16"
265 | },
266 | {
267 | "name": "react/stream",
268 | "version": "v0.4.1",
269 | "source": {
270 | "type": "git",
271 | "url": "https://github.com/reactphp/stream.git",
272 | "reference": "9db28e85a6fe7b57fad5e8c036f3434bcb8c8f60"
273 | },
274 | "dist": {
275 | "type": "zip",
276 | "url": "https://api.github.com/repos/reactphp/stream/zipball/9db28e85a6fe7b57fad5e8c036f3434bcb8c8f60",
277 | "reference": "9db28e85a6fe7b57fad5e8c036f3434bcb8c8f60",
278 | "shasum": ""
279 | },
280 | "require": {
281 | "evenement/evenement": "~2.0",
282 | "php": ">=5.4.0"
283 | },
284 | "suggest": {
285 | "react/event-loop": "0.4.*",
286 | "react/promise": "~2.0"
287 | },
288 | "type": "library",
289 | "extra": {
290 | "branch-alias": {
291 | "dev-master": "0.4-dev"
292 | }
293 | },
294 | "autoload": {
295 | "psr-4": {
296 | "React\\Stream\\": ""
297 | }
298 | },
299 | "notification-url": "https://packagist.org/downloads/",
300 | "license": [
301 | "MIT"
302 | ],
303 | "description": "Basic readable and writable stream interfaces that support piping.",
304 | "keywords": [
305 | "pipe",
306 | "stream"
307 | ],
308 | "time": "2014-03-30 17:19:02"
309 | }
310 | ],
311 | "packages-dev": [],
312 | "aliases": [],
313 | "minimum-stability": "stable",
314 | "stability-flags": [],
315 | "platform": [],
316 | "platform-dev": []
317 | }
318 |
--------------------------------------------------------------------------------
/examples/php-server/server.php:
--------------------------------------------------------------------------------
1 | on('request', function ($request, $response) use ($react) {
51 | $requestBody = '';
52 | $headers = $request->getHeaders();
53 | $contentLength = (int) $headers['Content-Length'];
54 | $receivedData = 0;
55 |
56 | $request->on('data', function ($data) use (
57 | $react,
58 | $request,
59 | $response,
60 | &$requestBody,
61 | &$receivedData,
62 | $contentLength
63 | ) {
64 | $requestBody .= $data;
65 | $receivedData += strlen($data);
66 | if ($receivedData >= $contentLength) {
67 | parse_str($requestBody, $requestData);
68 |
69 | $errors = validateRequest($requestData);
70 |
71 | if (count($errors)) {
72 | $response->writeHead(
73 | 400,
74 | ['Content-Type' => 'application/json']
75 | );
76 | $response->end(json_encode($errors));
77 | return;
78 | }
79 |
80 | $props = json_decode($requestData['props']);
81 |
82 | if ($requestData['renderType'] === 'static') {
83 | $reactFunction = 'renderStaticComponent';
84 | } else {
85 | $reactFunction = 'renderMountableComponent';
86 | }
87 |
88 | $markup = $react->$reactFunction(
89 | $requestData['componentPath'],
90 | $props
91 | );
92 |
93 | $response->writeHead(200, array('Content-Type' => 'text/html'));
94 | $response->end($markup);
95 | }
96 | });
97 | });
98 |
99 | $socket->listen($args['-p'] ?: 3000);
100 | $loop->run();
--------------------------------------------------------------------------------
/examples/v8.php:
--------------------------------------------------------------------------------
1 | renderAutoMountingComponent('./TestComponent'), PHP_EOL;
10 | echo $v8->renderMountableComponent('./TestComponent'), PHP_EOL;
11 | echo $v8->renderStaticComponent('./TestComponesnt'), PHP_EOL;
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 | ./tests/cases
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/React.php:
--------------------------------------------------------------------------------
1 | renderer = $renderer ?: new NullRenderer();
35 | $this->fragmentProvider = $fragmentProvider ?: new SynchronousRequireProvider();
36 | }
37 |
38 | /**
39 | * @param $componentPath
40 | * @param null $props
41 | * @param null $id
42 | * @return string
43 | */
44 | public function renderAutoMountingComponent($componentPath, $props = null, $id = null)
45 | {
46 | $containerId = $id ?: uniqid();
47 |
48 | return sprintf(
49 | "%s
",
50 | $containerId,
51 | $this->renderer->renderMountableComponent($componentPath, $props),
52 | $this->fragmentProvider->getReact(),
53 | $this->fragmentProvider->getComponent($componentPath),
54 | json_encode($props),
55 | json_encode($containerId)
56 | );
57 | }
58 |
59 | /**
60 | * @param $componentPath
61 | * @param array|void $props
62 | * @return string
63 | */
64 | public function renderMountableComponent($componentPath, $props = null)
65 | {
66 | return $this->renderer->renderMountableComponent($componentPath, $props);
67 | }
68 |
69 | /**
70 | * @param $componentPath
71 | * @param array|void $props
72 | * @return string
73 | */
74 | public function renderStaticComponent($componentPath, $props = null)
75 | {
76 | return $this->renderer->renderStaticComponent($componentPath, $props);
77 | }
78 | }
--------------------------------------------------------------------------------
/src/ReactFactory.php:
--------------------------------------------------------------------------------
1 | fragmentProvider = $fragmentProvider;
21 | }
22 |
23 | /**
24 | * @return \ReactJS\RuntimeFragmentProvider\ProviderInterface
25 | */
26 | public function getFragmentProvider()
27 | {
28 | return $this->fragmentProvider ?: new SynchronousRequireProvider();
29 | }
30 | }
--------------------------------------------------------------------------------
/src/Renderer/HTTPServerRenderer.php:
--------------------------------------------------------------------------------
1 | host = (string) $host;
55 | $this->port = (int) $port;
56 | $this->path = (string) $path;
57 | $this->ssl = (bool) $ssl;
58 | $this->logger = $logger;
59 | }
60 |
61 | /**
62 | * Renders a component that is able to be mounted via JavaScript in the browser
63 | * @param $componentPath
64 | * @param array|void $props
65 | * @return string
66 | */
67 | public function renderMountableComponent($componentPath, $props = null)
68 | {
69 | return $this->render('mountable', $componentPath, $props);
70 | }
71 |
72 | /**
73 | * Renders a static component unable to be mounted via JavaScript
74 | * @param $componentPath
75 | * @param array|void $props
76 | * @return string
77 | */
78 | public function renderStaticComponent($componentPath, $props = null)
79 | {
80 | return $this->render('static', $componentPath, $props);
81 | }
82 |
83 | /**
84 | * @param $reactRenderType
85 | * @param $componentPath
86 | * @param null $props
87 | * @return string
88 | */
89 | private function render($reactRenderType, $componentPath, $props = null)
90 | {
91 | $markup = '';
92 |
93 | $client = new Client();
94 |
95 | try {
96 | $response = $client->post(
97 | sprintf(
98 | "http%s://%s:%s/%s",
99 | $this->ssl ? 's' : '',
100 | $this->host,
101 | $this->port,
102 | ltrim($this->path, '/')
103 | ),
104 | [
105 | "body" => [
106 | "renderType" => $reactRenderType,
107 | "componentPath" => $componentPath,
108 | "props" => json_encode($props)
109 | ]
110 | ]
111 | );
112 |
113 | $markup = (string) $response->getBody();
114 | } catch (RequestException $e) {
115 | if ($this->logger instanceof LoggerInterface) {
116 | $this->logger->error($e->getMessage());
117 | }
118 | }
119 |
120 | return $markup;
121 | }
122 | }
--------------------------------------------------------------------------------
/src/Renderer/LoggingRendererTrait.php:
--------------------------------------------------------------------------------
1 | logger = $logger;
25 | }
26 |
27 | /**
28 | * @return \Psr\Log\LoggerInterface
29 | */
30 | public function getLogger()
31 | {
32 | return $this->logger;
33 | }
34 |
35 | /**
36 | * @param string $logType
37 | */
38 | public function setLogType($logType)
39 | {
40 | $this->logType = $logType;
41 | }
42 |
43 | /**
44 | * @return string
45 | */
46 | public function getLogType()
47 | {
48 | return $this->logType;
49 | }
50 |
51 | /**
52 | * @param $message
53 | * @param array $context
54 | */
55 | protected function log($message, array $context = [])
56 | {
57 | if ($this->logger instanceof LoggerInterface) {
58 | $this->logger->{$this->logType}($message, $context);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/Renderer/NodeProcessRenderer.php:
--------------------------------------------------------------------------------
1 | setBin($bin);
28 | $this->setSourceFiles($sourceFiles);
29 | if ($fragmentProvider) {
30 | $this->setFragmentProvider($fragmentProvider);
31 | }
32 | if ($logger) {
33 | $this->setLogger($logger);
34 | }
35 | }
36 |
37 | /**
38 | * Renders a component that is able to be mounted via JavaScript in the browser
39 | * @param $componentPath
40 | * @param array|void $props
41 | * @return string
42 | */
43 | public function renderMountableComponent($componentPath, $props = null)
44 | {
45 | return $this->getOutput(
46 | $this->getJavaScript(
47 | 'renderComponentToString',
48 | $componentPath,
49 | $props
50 | )
51 | );
52 | }
53 |
54 | /**
55 | * Renders a static component unable to be mounted via JavaScript
56 | * @param $componentPath
57 | * @param array|void $props
58 | * @return string
59 | */
60 | public function renderStaticComponent($componentPath, $props = null)
61 | {
62 | return $this->getOutput(
63 | $this->getJavaScript(
64 | 'renderComponentToStaticMarkup',
65 | $componentPath,
66 | $props
67 | )
68 | );
69 | }
70 |
71 | /**
72 | * @param $reactFunction
73 | * @param $componentPath
74 | * @param null $props
75 | * @return string
76 | */
77 | protected function getJavaScript($reactFunction, $componentPath, $props = null)
78 | {
79 | $fragmentProvider = $this->getFragmentProvider();
80 |
81 | $javascript = [];
82 |
83 | foreach ($this->sourceFiles as $sourceFile) {
84 | $javascript[] = file_get_contents($sourceFile) . ";";
85 | }
86 |
87 | $javascript[] = sprintf(
88 | "console.log(%s.%s(%s(%s)));",
89 | $fragmentProvider->getReact(),
90 | $reactFunction,
91 | $fragmentProvider->getComponent($componentPath),
92 | json_encode($props)
93 | );
94 |
95 | return implode('', $javascript);
96 | }
97 | }
--------------------------------------------------------------------------------
/src/Renderer/NullRenderer.php:
--------------------------------------------------------------------------------
1 | sourceFiles = $sourceFiles;
39 | }
40 |
41 | /**
42 | * @return array|\Traversable
43 | */
44 | public function getSourceFiles()
45 | {
46 | return $this->sourceFiles;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/Renderer/StdInProcessRendererTrait.php:
--------------------------------------------------------------------------------
1 | bin = $bin;
25 | }
26 |
27 | /**
28 | * @return mixed
29 | */
30 | public function getBin()
31 | {
32 | return $this->bin;
33 | }
34 |
35 | /**
36 | * @return \Symfony\Component\Process\Process
37 | */
38 | protected function getProcess()
39 | {
40 | return new Process($this->bin);
41 | }
42 |
43 | /**
44 | * @param string $input
45 | * @return string
46 | */
47 | protected function getOutput($input)
48 | {
49 | return $this->run($input)->getOutput();
50 | }
51 |
52 | /**
53 | * @param string $input
54 | * @return \Symfony\Component\Process\Process
55 | */
56 | protected function run($input)
57 | {
58 | $process = $this->getProcess();
59 | $process->setInput($input);
60 | $process->run();
61 |
62 | if ($error = $process->getErrorOutput()) {
63 | $this->log('Error during rendering', [
64 | 'stderr' => $error
65 | ]);
66 | }
67 | return $process;
68 | }
69 | }
--------------------------------------------------------------------------------
/src/Renderer/V8JsRenderer.php:
--------------------------------------------------------------------------------
1 | setSourceFiles($sourceFiles);
47 | if ($fragmentProvider) {
48 | $this->setFragmentProvider($fragmentProvider);
49 | }
50 | if ($logger) {
51 | $this->setLogger($logger);
52 | }
53 | $this->v8 = $v8 ?: new V8Js;
54 | }
55 |
56 | /**
57 | * Renders a component that is able to be mounted via JavaScript in the browser
58 | * @param $componentPath
59 | * @param array|void $props
60 | * @return string
61 | */
62 | public function renderMountableComponent($componentPath, $props = null)
63 | {
64 | return $this->render("renderComponentToString", $componentPath, $props);
65 | }
66 |
67 | /**
68 | * Renders a static component unable to be mounted via JavaScript
69 | * @param $componentPath
70 | * @param array|void $props
71 | * @return string
72 | */
73 | public function renderStaticComponent($componentPath, $props = null)
74 | {
75 | return $this->render("renderComponentToStaticMarkup", $componentPath, $props);
76 | }
77 |
78 | /**
79 | * @param $reactFunction
80 | * @param $componentPath
81 | * @param null $props
82 | * @return string
83 | * @throws \Exception
84 | */
85 | private function render($reactFunction, $componentPath, $props = null)
86 | {
87 | $javascript = $this->getJavaScript($reactFunction, $componentPath, $props);
88 |
89 | $markup = '';
90 |
91 | try {
92 | ob_start();
93 | $markup = $this->v8->executeString($javascript);
94 | $loggableErrors = ob_get_clean();
95 |
96 | if ($loggableErrors) {
97 | $this->log(
98 | "Errors in v8 javascript execution",
99 | ["errors" => $loggableErrors]
100 | );
101 | }
102 |
103 | if (!is_string($markup)) {
104 | throw new RuntimeException("Value returned from v8 executeString isn't a string");
105 | }
106 | } catch (\Exception $e) {
107 | $this->log($e->getMessage());
108 |
109 | if ($reactFunction === 'renderComponentToStaticMarkup') {
110 | throw $e;
111 | }
112 | }
113 |
114 | return $markup;
115 | }
116 |
117 | /**
118 | * @param $reactFunction
119 | * @param $componentPath
120 | * @param $props
121 | * @return array
122 | */
123 | protected function getJavaScript($reactFunction, $componentPath, $props)
124 | {
125 | $fragmentProvider = $this->getFragmentProvider();
126 |
127 | $javascript = [];
128 |
129 | $javascript[] = "var console = { warn: print, error: print };";
130 |
131 | // Clear any module loaders
132 | if (method_exists($this->v8, 'setModuleLoader') && $fragmentProvider instanceof SynchronousRequireProvider) {
133 | $javascript[] = "function require() {}";
134 | $javascript[] = "var require = null;";
135 | }
136 |
137 | foreach ($this->sourceFiles as $sourceFile) {
138 | $javascript[] = file_get_contents($sourceFile) . ";";
139 | }
140 |
141 | $javascript[] = sprintf(
142 | "%s.%s(%s(%s));",
143 | $fragmentProvider->getReact(),
144 | $reactFunction,
145 | $fragmentProvider->getComponent($componentPath),
146 | json_encode($props)
147 | );
148 |
149 | return implode("\n", $javascript);
150 | }
151 | }
--------------------------------------------------------------------------------
/src/RuntimeFragmentProvider/GlobalObjectProvider.php:
--------------------------------------------------------------------------------
1 | renderer = new V8JsRenderer(
21 | [__DIR__ . '/../../fixtures/bundle.js']
22 | );
23 | }
24 |
25 | public function testRenderMountableComponent()
26 | {
27 | $markup = $this->renderer->renderMountableComponent('./TestComponent');
28 |
29 | $this->assertContains(
30 | 'Some testing content',
31 | $markup
32 | );
33 |
34 | $this->assertContains(
35 | 'data-reactid',
36 | $markup
37 | );
38 |
39 | $this->assertContains(
40 | 'data-react-checksum',
41 | $markup
42 | );
43 | }
44 |
45 | /**
46 | * @expectedException \V8JsScriptException
47 | * @expectedExceptionMessage Cannot find module './test'
48 | */
49 | public function testStaticDoesThrowExceptionOnMissingComponent()
50 | {
51 | $this->renderer->renderStaticComponent('./test');
52 | }
53 |
54 | public function testMountableDoesntThrowExceptionOnMissingComponent()
55 | {
56 | try {
57 | $this->assertEquals(
58 | '',
59 | $this->renderer->renderMountableComponent('./test')
60 | );
61 | } catch (\Exception $e) {
62 | $this->fail('Exception thrown when meant not to');
63 | }
64 | }
65 |
66 | public function testRenderStaticComponent()
67 | {
68 | $markup = $this->renderer->renderStaticComponent('./TestComponent');
69 |
70 | $this->assertContains(
71 | 'Some testing content',
72 | $markup
73 | );
74 |
75 | $this->assertNotContains(
76 | 'data-reactid',
77 | $markup
78 | );
79 |
80 | $this->assertNotContains(
81 | 'data-react-checksum',
82 | $markup
83 | );
84 | }
85 | }
--------------------------------------------------------------------------------
/tests/fixtures/TestComponent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react');
4 |
5 | module.exports = React.createClass( {
6 | render: function() {
7 | return React.DOM.span( null, "Some testing content" );
8 | }
9 | } );
--------------------------------------------------------------------------------
/tests/fixtures/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactjs-php-render-tests",
3 | "description": "React for unit tests",
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "react": "~0.10",
7 | "browserify": "~3.26.0"
8 | },
9 | "scripts": {
10 | "build": "NODE_ENV=production browserify -r react -r ./TestComponent > bundle.js"
11 | }
12 | }
--------------------------------------------------------------------------------