PHP Like a Pro: Part 2

In part one of this series I imparted some serious knowledge and discussed a lot of theoretical bullshit. Not all of it went over well, and not all of it was PHP specific. A lot of the stuff we talked about was just general programming advice. This part will be more concrete and hands on. Before we start, let’s make sure we are all on the same page. Lets talk about your stack.

The development machine you are sitting on right now – is it running a LAMP stack? Or is it MAMP? Or worse, WAMP, WIMP or some other abomination?

Here is something to chew on: chances are you are going to be deploying your shitty PHP app (all software is shitty, not just yours so don’t take this personal) to a web host that is running LAMP stack. Even though PHP ought to run the same everywhere, there are going to be quirks between platforms. You should be running the same stack as your production environment. And most importantly you should be running the same stack as me.

Why? Well, let’s say that for some strange reason you want to follow this guide and code along with me. I’m going to say “now do XYZ”, and then you’re gonna write a comment like “But how do I XYZ on a Mac?” and then I will have to take out my MacBook, and fucking wait for homebrew to compile twenty seven things. And then all I’m gonna find out is that you are bugged more than me because you’re running OSX Snoop Lion, whereas I’m already on OSX Space Leopard and one of us would totally need to up-down-grade or something.

So we are gonna bypass that. If you are not sitting on a LAMP right now, go fucking download Vagrant. In fact, download it anyway and we will set it up to keep your PHP shit away from your normal shit.

Setting Up a Sweet-Ass Development Environment

I should probably explain Vagrant here, though we are going to get side tracked by this. Vagrant will let you set up a virtual machine in about 5 minutes. It lets you go from nothing, to a full fledged virtual linux box running inside your computer in minutes, with no installers, no fucking around, and no 800GB image downloads.

Here is what you do. First, pick a folder somewhere on your system where you want the files that you share between the VM (say ~/vagrant, or maybe %USERPROFILE%\Documents\vagrant if on Widnows) then open a terminal:

mkdir ~/vagrant
cd ~/vagrant
vagrant box add base http://files.vagrantup.com/lucid32.box
vagrant init
vagrant up
vagrant ssh

If all went well, you should now be sitting on a freshly installed linux box prompt. Yeah, it is that easy… Unless you are on Windows, where you actually have to futz around with PuTTY like an idiot for another five minutes. It pretty much goes like this:

  1. Run PuTTYGen
  2. Load %USERPROFILE%\.vagrant.d\insecure_private_key
  3. Save private key as idontevencare.ppk
  4. Pull up Putty, use localhost and port 2222
  5. On the sidebar go to SSH->Auth and load the file you just created
  6. Save the profile so you don’t have to do it again and hit connect
  7. Log in as vagrant

Now you have the L part of the equation, and it is time to install the AMP part. You can actually get pretty fancy with Vagrant – it supports provisioning with puppet and cheff but we don’t need that. We’ll just do it the old-fashioned way:

sudo aptitude update
sudo aptitude install php5 php-mysql apache2 mysql-server

Now we are all set. All is left is to make our freshly minted server accessible from your host system. So head back to that folder you picked to dump your Vagrant shit into and open the Vagrantfile that was created there and un-comment the following line:

config.vm.forward_port 80, 8080

This will let you access the virtual server by hitting http://localhost:8080. If you’re following along, you can hit that link to see if it works. It shouldn’t, because the config file change won’t take effect until you restart your VM with the following command:

vagrant reload

Here is a bonus trick: move apache document root from /var/www to /vagrant/whatever. Why? Because the /vagrant directory is shared between the VM and host. This means you can edit the file directly on your host OS, using your favorite editor or IDE.

Now we all have a nice LAMP server, let’s move on to actual PHP stuff. I’m already close to a thousand words in, and I haven’t even started getting on topic. Hey guys, I have an idea – I’m gonna start a series of posts about PHP and then talk about everything in the fucking word rather than this damnable language!

Tools of the Trade

At the pace this is going we’re definitely not writing any actual code today, so let’s talk some more about setup. Here is what I want to use for this project:

But Luke, all of this for a pastebin?

Shut your mouth, you knew what this was. I’m doing a thing where we are going to pull in all these tools knowing full well its an overkill for the sole purpose of learning about them.

The first two items on your list are development time dependencies, so I suggest installing them globally.

PHPUnit and PHPDocumentor

Why did I choose PHPUnit and PHPDocumentor? There are many other popular projects out there – like SimpleTest for example. So why these two? Because I said so. Also, these two projects are more or less the de-facto industry standards. They are ubiquitous and by far the most popular choices. So if you are going to be doing anything with PHP, you will see them crop up sooner or later.

We could install them on a per-project basis, but I find that it is best to just bite the bullet and load them system wide, and save you some hassle later. To do that we will need pear which is old and uncool package manager for PHP projects. It’s not very much liked, because unlike equivalent package managers for other languages (like gem for Ruby and npm for Node.js) you can’t just register your project with it. You have to be a cool dude, or do sexual favors for the project founders or something like that.

Anyway, let’s install pear the usual way:

sudo aptitude install php-pear

Now let’s download PHPUnit:

sudo pear channel-update pear.php.net
sudo pear upgrade-all
sudo pear config-set auto_discover 1
sudo pear install pear.phpunit.de/PHPUnit

Yeah, did I mention the interface on that thing is totally great? I honestly don’t even want to know what is the deal with these channels and auto discoveries – the whole thing is bizarre and byzantine. Also buggy.

You will likely encounter this error because I did:

Duplicate package channel://pear.phpunit.de/File_Iterator-1.3.3 found
Duplicate package channel://pear.phpunit.de/File_Iterator-1.3.2 found
install failed

Here is the solution:

sudo pear clear-cache
sudo pear install phpunit/File_Iterator
sudo pear install phpunit/Text_Template
sudo pear install --force --alldeps pear.phpunit.de/PHPUnit

This should now get you a semi-working version. If it is still bugging out when trying to run tests, do this:

sudo pear channel-discover components.ez.no
sudo pear install phpunit/phpcpd

sudo pear install --force phpunit/PHP_File_Iterator-1.3.2
sudo pear install --force phpunit/PHP_Timer-1.0.3
sudo pear install --force phpunit/Text_Template-1.1.2
sudo pear install --force phpunit/PHP_CodeCoverage-1.1.2
sudo pear install --force phpunit/PHP_TokenStream-1.1.2

I’d explain, but honestly – I don’t actually give a flying fuck what happened there. The less I need to use pear, the more sanity I retain and therefore I will refrain from delving into this issue. Suffice to say this quick fix worked for me.

If you are interested (or a glutton for punishment) here is the rundown of the situation: for some odd reason PHPUnit 3.6 has wrong dependencies marked in the Pear package system. When you install PHPUnit via Pear, it looks at you PHP version and if you have 5.3.3 it installs the latest version which is 3.7. If you don’t, it installs 3.6. Some of the dependencies broke backwards compatibility with 3.6 some time ago so logically Pear should download the latest compatible versions. But for the above-listed packages it downloads latest and greatest which causes PHPUnit 3.6 fail in unpredictably fun ways. Or in other words, pear is shit package manager.

PHPDocumentor can be installed without any major advetures:

sudo pear channel-discover pear.phpdoc.org
sudo pear install phpdoc/phpDocumentor-alpha

The nice thing about having installed these things globally is that you now have them in your path, available as nifty commands phpunit and phpdoc respectively. I will talk about these in more detail when we actually get to use them (which may actually happen in the next eternity or so).

Composer: managing run-time dependencies

Let’s talk about run time dependencies. I mentioned we will be using Twig and RedBean which are a templating framework and an ORM respectively. I could try installing these globally, but they are really project specific bundles of code. Next project you will be working on might require you to use Doctrine or Propel for example. And then what? You’re going to have all these different ORM frameworks crufting up your dev-space.

Granted, you could always roll a new Vagrant server for the next project and start clean, but… Well, PHP community came up with a solution for this particular problem – a run time dependency manager named Composer. It is the new and hot thing as compared to the old and busted Pear.

How is Composer different from Pear, Gem, Pip or Npm tools? It manages dependencies on a project level, not at a system level. You tell it what packages you need for this specific project, and it installs them into the project folder, already bundled up and ready for deployment. How do you install this wonder?

cd /tmp
curl -s https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

That’s it – from this point on, it will be available system wide using the composer command.

You may want to wrap this up

Quick note before we start plowing ahead. This is a good spot to wrap up your vagrant machine into a box. Vagrant lets you save your current VM into a file that you can deploy somewhere else later. That’s sort of where it got its name from – you can build a machine once and then distribute it to all your buddies yielding an identical development environment for all of you, regardless of what OS and software each person is actually running.

To save the state, you just issue a quick command (on the host OS):

vagrant package

This will put a package.box file in ~/vagrant/ or wherever your Vagrantfile lives. This box contains the entire environment the exact way you set it up. For us, this would mean a complete LAMP stack, PHPUnit, PHPDocumentor and Composer all set up and ready to go. So let’s save this file for later in case we will want to start a new project from scratch at some point in the near future.

When the day you are ready to tear down your current vagrant and start over comes, just do this:

mkdir ~/newvagrant
cd ~/newvagrant
vagrant box add lamp /path/to/package.box
vagrant init

Then edit your ~/newvagrant/Vagrantfile to be:

Vagrant::Config.run do |config|
  config.vm.box = "lamp"
  config.vm.forward_port 80, 8080
end

Then just boot it up it with vagrant up and you should be ready to go.

Twig and RedBean

Why are we using these things again? Well, I guess the best way to explain this is to give you an example. Twig is a feature-full, but easy to use templating engine with neat features such as auto-escaping (in case you forget), and RedBean is a completely hands-off ORM that almost completely removes the need for writing SQL statements by hand. Combined together, they allow you to write code that is incredibly succinct, clean and at the same time relatively safe.

For example, you could define a template file (let’s call it paste.html) like this:

{% include header.html %}
  

PASTE #{{ id }}

{{ content }} new paste {% include footer.html %}

Then somewhere else in our code we could render it like this:

// fetch paste from the db
$paste = R::load('paste', $id);
// render it using paste.html
echo $twig->render('paste.twig', array('id' => paste->id, 'content' => paste->content));

This is of course an oversimplified pseudo-code. There is a little bit more setup but you can easily see the benefits here. Your HTML lives separately from PHP code in files that cannot be executed by themselves. What you probably don’t see in this this bit of code is the escaping I was harping about so much last week. That’s because it’s not necessary. Twig can be configured to auto-escape all template variables by default. RedBean automatically sanitizes all the input you pas into it. It’s pretty much auto-magical.

Let’s get down to it

This post is getting a little bit long, but I want to accomplish one more thing today – setting up your project. This way we will be ready to go to actually throw down some code in next installment.

So let’s visit our project folder and set a few things up:

cd /vagrant/www
git init
touch composer.json
touch .gitignore

I probably should not say this, but git init should be the absolute first command you issue when embarking on any kind of creative project. I said this before, but it bears repeating over and over and over again until it becomes your mantra:

  • if time spent making it >= 5min, put it under version control

Fortunately for us, PHP does not generate that many cruft files we would need to exclude from our repository. So our .gitignore is only going to have a single line:

vendor/

What is this directory? That’s where Composer is going to dump all the dependencies. You don’t want to commit those things with your project – it is a waste of space and time. If you publish your code later, contributors will be able to automatically fetch these dependencies with Composer. That’s one of the reasons we are using it. So lets set it up.

Inside composer.json we put references to Twig and RedBean like this:

{
    "require": {
        "twig/twig": "1.*",
        "gabordemooij/redbean": "dev-master"
    }
}

Make sure you don’t eat up any brackets or commas – the file needs to be a valid json for the magic to work.

Finally, let’s allow composer to do it’s work:

composer install

You should now see new files and folders magically appearing in your folder:

  • The vendor/ directory contains all the files necessary to use Twig and RedBean
  • The composer.lock file “locks” the project to current versions the dependencies. You will want to commit it to your version control and publish it with your project code. This way, someone who downloads your code will get the exact same versions of Twig and RedBean as you (eg. same commit for RedBean and same minor version for Twig).

All that is left to do now, is to git it all up:

git add .
git commit -m "First commit"

And there you have it. We are now ready to go, we all have uniform development environment and we are all ready to write some code. Which will happen next time… Maybe.

One more thing…

I almost forgot – if you want to shut down your vagrant instance you have two options:

  1. vagrant suspend will “hibernate” your VM to disk. You can then vagrant resume with about a 10 sec boot time. The only downside is that it will use extra disk space to save current state but this should not be an issue on most machines.
  2. vagrant halt will perform a graceful shut down. You will have to use vagrant up to power it up again. You probably want to do this if your shit is all cray, and you want to do a clean reboot.

I’m hoping this is helpful and/or entertaining because I have at least one or two more of these in me (depending on how many times I get side tracked and go on a random tangent).

This entry was posted in Uncategorized. Bookmark the permalink.



4 Responses to PHP Like a Pro: Part 2

  1. Holy shit, Luke!!! Vagrant is awesome! I will definitely be using this a lot in the future.

    Reply  |  Quote
  2. Luke Maciak UNITED STATES Google Chrome Linux Terminalist says:

    @ Chris Wellons:

    Yeah I’m loving it. Since I found out about it, there is like no need for me to even bother setting up php/apache/mysql or any other unixy environment on Windows/Mac :P

    Also, this might be a way better method of getting CLISP environment working on Windows than Cygwin.

    Reply  |  Quote
  3. Ron NEW ZEALAND Mozilla Firefox Linux says:

    Ill second that, Vagrant looks to be an intersting take on virtual machines

    Reply  |  Quote
  4. Nathan UNITED KINGDOM Google Chrome Windows says:

    Finally got around to trying Vagrant on my Windows machine at work, it’s excellent! Was using EasyPHP before this. Love that I can better match my production environment and have access to powerful Unix commands (without installing Cygwin)!
    Thanks for the clear – and amusing – instructions. I’ll be using this on OS X and Windows for my dev environment.
    Trying Composer now. I’ve seen it mentioned in PHP ‘best practise’ articles but as I’m unfamiliar with other dependency managers I never grokked it. Your post made it clear. Love the cleanliness of managing dependencies on a project level.
    http://www.phptherightway.com is a useful starting point but a post like this makes these tools much more accessible to people like me who’ve not used them before.
    Thanks for another excellent post!

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *