Use PHP with your Yeoman dev server
Note: I haven't used this stack for a couple of years. Judging by the comments, this protip has gone fairly stale. Take what you can, but just know that YMMV.
Ever needed to use a PHP script in your Yeoman project? It's quite straightforward to do so while keeping all of the goodness that Yeoman brings together for you (particularly live reloading).
The integration is accomplished via a middleware by Felix Gnass named gateway. Gateway enables you to specify CGI handlers for requests matching certain extensions (.php in our case). Mr. Gnass wrote a blog post on this protip's topic, but didn't include step-by-step instructions for the middleware integration, which took me a while to figure out.
Example code
https://github.com/falsetto/php-from-yeoman
Generate an app with Yeoman
$ mkdir php-from-yeoman
$ cd php-from-yeoman
$ yo webapp
Ensure that php-cgi is in your $PATH
$ which php-cgi
If you get php-cgi not found
, here's how to install it using Homebrew on OS X (for other OS's, Google is your friend):
brew tap homebrew/dupes
brew tap josegonzalez/homebrew-php
brew install php54
Setup gateway module
$ npm install gateway
Modify Gruntfile.js
by adding the following near the top:
var gateway = require('gateway');
Modify the array returned by the function at connect.livereload.options.middleware
to look like this:
middleware: function (connect) {
return [
lrSnippet,
gateway(__dirname + '/app', {
'.php': 'php-cgi'
}),
mountFolder(connect, '.tmp'),
mountFolder(connect, 'app')
];
}
Rename app/index.html and test
$ mv app/index.html app/index.php
Add <?php echo "<h1>Hello from PHP!</h1>";
within the body
tag of app/index.php
.
Then fire up your development server:
$ grunt server
Assuming that your browser launched and loaded http://localhost:9000/
, you should see Hello from PHP! on the page.
Make some changes to app/index.php, save the file, and your browser should automatically reload.
Note: due a to naïve conditional in the livereload library, live reloading will only work for PHP files when the URL ends with a '/' (so basically, index.php files).
Written by Jedidiah Hurt
Related protips
15 Responses
Great tip, worked like a charm, I was using yeoman with angularjs and needed to bring in some php for server side support and your tip was very helpful and well written.
Cheers!
@davidchase03, glad to hear it!
Please provide a date for this article. It is incredibly disorienting to read blogs about cutting edge stuff without knowing if it's up to date or not.
Also, your solution worked perfectly, thank you for this :) Much obliged
Great tip! Do you have any other tips about using a MAMP server to point to a Yeoman generated app? I mean, I don't want to use localhost:9000 anymore. I want my MAMP domain alias to point to /app and still be able to test with livereload. Is that possible?
@wjonthomas: Glad it helped!
Unfortunately, I've only investigated the process of getting a node.js server to interpret PHP files using the php-cgi cli. Getting a MAMP server (Apache+PHP) to load and execute node.js code based off of a Gruntfile would be a wholly different thing that I haven't tried.
I'd be very interested to know if you figure out how to do it.
@falsetto I think a lot of people would be interested to see that. I fooled around for a bit. Seems like you can easer use the grunt connect server, or remove all of that convenience and use your own server. You lose a lot of the convenience of just running grunt server and being on your way though. I will definitely report back if I come across any ways to improve the workflow with Grunt/MAMP.
I created a patch to edit your Gruntfile.js to config the server to run on /
directory instead of app/
(useful for legacy project). See: https://gist.github.com/edouard-lopez/6397228
Thanks!! Time saver!
I'm interested in streamlining things like that as well. I think, though, that using pow might be a good option. This could give you the hostname flexibility, and also the convenience of firing things up with a single grunt watch
command. I'll report back if I find success, but wanted to put the idea out there for someone to find if I wander off course :)
There's no definition of lrSnippet anywhere so I got the following warning:
Running "connect:livereload" (connect) task
Warning: lrSnippet is not defined Use --force to continue.
I added the following at the top of Gruntfile.js:
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
and installed grunt-contrib-livereload and saved to package.json with the following from the terminal:
npm install --save-dev grunt-contrib-livereload
Then I discovered I was missing other dependencies and added the following to Gruntfile:
var path = require('path');
var mountFolder = function folderMount(connect, point) {
return connect.static(path.resolve(point));
};
At this point I see an Internal Server Error 500. After some fiddling I found that changing the following:
gateway(__dirname + '/app', {
'.php': 'php-cgi'
}),
to:
gateway('<%= config.app %>', {
'.php': 'php-cgi'
}),
finally got everything in order and grunt serve ran successfully without a 500 error, although my browser only says: Cannot Get / Here's a gist of my gruntfile: https://gist.github.com/anthonygreco/a92333ed5e3ffe4dd1a9 any idea what's missing here? Also this is the feedback from grunt:
Running "connect:livereload" (connect) task
Verifying property connect.livereload exists in config...OK
File: [no files]
Options: protocol="http", port=9000, hostname="localhost", base=".", directory=null, keepalive=false, debug=false, livereload=35729, open, useAvailablePort=false, middleware=undefined
Started connect web server on http://localhost:9000
Not sure why it says middleware undefined either. :\ Really wish I could easily spin up a PHP webapp that's not just php served from one "api" folder and instead the entire app. Any assistance here is greatly appreciated.
Doesn't work with latest yeoman webapp
lrSnippet is not defined
mountFolder is not defined
// Chris D. 14-Jan-2015
Yesterday worked like a charm, today not. For some reason the app doesn't find bower components anymore. If I change my php file back to html and then Grunftile back to original, it all works.
This leaves me wondering: this can't be the easiest way to develop with php on 2015?
EDIT:
I also get "connect: res.headerSent: use standard res.headersSent" when I run grunt serve
EDIT EDIT:
Oh, I'm so incredibly noob. I 'm pretty new with this stuff so most of the time I just copy/paste the rows to various places not really understanding the process. I didn't realise that I'm not supposed to replace "connect.livereload.options.middleware" with
return [
lrSnippet,
gateway(__dirname + '/app', {
'.php': 'php-cgi'
}),
mountFolder(connect, '.tmp'),
mountFolder(connect, 'app')
];
but leave the lines
connect.static('.tmp'),
connect().use('/bowercomponents', connect.static('./bowercomponents')),
connect.static(config.app),
there.
Now it works again. However, there is a weird behavior: the browser downloads index.php on every livereload.
Any ideas?
I don't find "connect.livereload.options.middleware"
Where is this ?
Hey @abumalick, here's the line from the finished file: https://github.com/falsetto/php-from-yeoman/blob/master/Gruntfile.js#L58
I haven't used this dev environment for a couple years now, so YMMV.
Good luck!
-Jedidiah