Garrett St. John

I am a web developer and partner at Bold. This is where I share my thoughts, discoveries and other random bits.

Setting up a New Project Database in Homestead with Envoy

May 23, 2014

If you’ve just started using Laravel Homestead you know just how easy it makes getting started on a new project. On my first attempt I was up and running in under five minutes…very cool!

While adding a new project today I realized there isn’t a built-in way to do project-specific provisioning. There are a few tasks I do on nearly every project and I’d prefer to not have to jump into the VM to do them (mostly because I have to always look up the commands). Enter Envoy.

Nearly every site has a database. Why not automate its creation? Envoy can take care of that in a snap.

MySQL

@servers(['vm' => '-p 2222 vagrant@127.0.0.1'])

@task('init-local', ['on' => 'vm'])
    mysql -u homestead -psecret -e "create database <db_name>";
@endtask

Postgres

@servers(['vm' => '-p 2222 vagrant@127.0.0.1'])

@task('init-local', ['on' => 'vm'])
    echo "*:*:*:*:secret" > ~/.pgpass
    chmod 600 ~/.pgpass
    createdb -h 127.0.0.1 -U homestead -O homestead <db_name>
    rm ~/.pgpass
@endtask

This is just the beginning of what you could do for a new project within Homestead. Other obvious tasks might be migrating and seeding the database, running custom Artisan commands, or even other sync’d shell scripts. It’s a breeze!

Self-Updating Composer in Production using Laravel Envoy

May 21, 2014

I was deploying a site today with Laravel Envoy and noticed that Composer was complaining about using a build older than 30 days old. Logging in manually and running the self-update is totally doable, but why not use Envoy to make the update? I added the following to my deployment script:

@task('deploy', ['on' => 'web'])
    composer self-update
    git reset --hard
    git checkout master
    git pull origin master
    composer install --no-dev
@endtask

However, I quickly found that the web user didn’t have the appropriate permissions to update Composer when installed globally to /usr/local/bin/composer.

[user@domain.com]: [Composer\Downloader\FilesystemException]
  Filesystem exception:
  Composer update failed: the "/usr/local/bin/composer" file could not be written

The user does have sudo ability, though, so I tried prefixing the command with sudo. Unfortunately the command then prompted for a password which Envoy can’t handle. To get around this issue I dug in deeper and modified the sudoers file:

$ sudo visudo
[sudo] password for <user>:

Inside the file I added a line which allows any user in the ‘sudo’ group to run composer as root without it requesting a password. That line looks something like this:

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL
%sudo   ALL=(ALL) NOPASSWD: /usr/local/bin/composer

This new line is pretty cryptic, so let’s break it down.

%sudo

Group name, must be prefixed with % to signify this rule is for a group. Without the % it will be considered a user name.

ALL=

Host list. This gives access to all hosts and can be restricted down to only certain specified IPs or hosts.

(ALL)

Operator list. This is a list of users the sudoer must be running the command as.

NOPASSWD:

Tag list. In this case, we specify to not request a password on execution.

/usr/local/bin/composer

Command list. The command(s) that are available to be executed with root privileges.

This can be set to “ALL” to allow access to all commands (dangerous!)

Set to “/usr/local/bin/composer self-update” to only allow the user to run the self-update command.

You can set the parameter to “/usr/local/bin/composer self-update,/usr/local/bin/composer install” to allow the user to self-update or install with root privileges.

Lastly, “/usr/local/bin/composer s*” would allow the user to run search, self-update, show, and status with root privileges. Pretty cool!

I saved the file and then re-ran my Envoy script…voila!

$ envoy run deploy
[user@domain.com]: Updating to version 0c85ca426d6e8235366340f29ad0e6aab1747b83.
    Downloading: 100%
Use composer self-update --rollback to return to version 1efa02a7ab43b7fc555dccb7d31294acbc62bbeb
...

Using UUIDs with Laravel’s Eloquent ORM

January 16, 2014

By default, Eloquent uses an auto-incrementing integer as the primary key for its tables. While most of the time this is totally acceptable, sometimes there is a need for primary keys to be less predictable.

Example: Table Reservations

You are writing an application for table reservations at a restaurant. You would likely have a database table that holds those reservations and ties them to a physical table and user account.

CREATE TABLE `reservations` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) unsigned NOT NULL,
  `table_id` int(11) unsigned NOT NULL,
  `reservation_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `table_id` (`table_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

If you were to create a way to display existing reservations at a given URL, say http://acmereservations.com/reservation/15 where 15 refers to the `reservations`.`id` field, you can see how it would be very easy to simply bump that number up to 16 and see someone else’s reservation and perhaps even cancel it. For the sake of simplicity we’ll ignore the fact that some authentication and access control can prevent this from happening.

Why UUID?

UUID is a uniquely generated 36 character string and looks something like: 22beb489-2ba9-44c8-b189-5855e1d4d1ad. While I say that the UUID is unique, that’s not entirely true. Let’s just say the likelihood of duplicates is extremely small. Along with being unique, it’s also very unpredictable. You can see how it would be much harder to guess other reservation IDs given a URL of http://acmereservations.com/reservation/22beb489-2ba9-44c8-b189-5855e1d4d1ad.

Secondarily, UUIDs allow site owners to mask the number of records in their database tables. If your registration ID is 15 you could assume there are only 14 other reservations and maybe this isn’t the best place to eat. A UUID will mask the number of records in a table with the generated string.

So how do we use UUIDs with Eloquent?

It turns out it’s not overly difficult. I would suggest the best way is for all Eloquent models needing a UUID to extend a base model that implements the following functionality:

<?php

/**
 * This is a great UUID generator package available on Composer
 * but you can generate your UUID however you see fit.
 */
use Rhumsaa\Uuid\Uuid;

class UuidModel extends Eloquent
{
    /**
     * Indicates if the IDs are auto-incrementing.
     *
     * @var bool
     */
    public $incrementing = false;

    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        /**
         * Attach to the 'creating' Model Event to provide a UUID
         * for the `id` field (provided by $model->getKeyName())
         */
        static::creating(function ($model) {
            $model->{$model->getKeyName()} = (string)$model->generateNewId();
        });
    }

    /**
     * Get a new version 4 (random) UUID.
     *
     * @return \Rhumsaa\Uuid\Uuid
     */
    public function generateNewId()
    {
        return Uuid::uuid4();
    }
}

Now, all you have to do is extend the UuidModel class for your models and the UUID will be set automatically on the primary key before creation.

<?php

class Reservation extends UuidModel
{
    ...
}

It’s worth noting that you will need to change your database schema to accommodate the UUID. For our `reservations` table, we would revise it like so:

CREATE TABLE `reservations` (
  `id` char(36) NOT NULL DEFAULT '',
  `user_id` int(11) unsigned NOT NULL,
  `table_id` int(11) unsigned NOT NULL,
  `reservation_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `table_id` (`table_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

And, that’s actually it! Thanks to r15ch13 for the vast majority of the code involved. If you have any thoughts or a different way to approach this, let me know in the comments below.

Update [1/16/2014]:

It’s worth updating here that I did have some issues when running tests with PHPUnit. The first test would always work as expected, however, the second test wouldn’t add in the UUID on the primary key. I don’t know what is going on here, but it seems to have something to do with PHPUnit since it worked fine when run inside of Laravel. To get around the issue I pulled the event declarations out of the UuidModel and put them into a dedicated events.php file like so:

<?php

$models = ['Reservation', 'User', 'Table'];

foreach ($models as $model) {
    $model::creating(function ($model) {
        $model->{$model->getKeyName()} = (string)Uuid::uuid4();
    });
}

I then revised the UuidModel as follows:

<?php

class UuidModel extends \Eloquent
{
    /**
     * Indicates if the IDs are auto-incrementing.
     *
     * @var bool
     */
    public $incrementing = false;

}

Using Composer with HHVM on Mac OS X

January 14, 2014

What is HHVM?

HHVM stands for HipHop Virtual Machine, the Facebook PHP execution engine. It was originally created to save resources on Facebook servers and has proven to increase PHP execution speeds significantly.

Why Composer on HHVM?

Due to its ability to improve the execution speed of PHP code, HHVM can also greatly increase the execution speed of Composer. This is because Composer is a PHAR file, or PHP Archive. Composer can feel quite slow at times and originally I thought this was due to networking speeds and how quickly packages could be pulled down from GitHub, but the simple comparison below proves that’s not the case.

Clocking Composer with and without HHVM

I’m clocking a `composer update` on a project I am currently working on. There were no new dependencies added so all Composer is doing is checking dependencies and building the updated autoload.php file. Network latency should have very little to no effect on the outcome.

Composer with PHP:

$ time php /usr/local/bin/composer update
...
real	0m54.441s
user	0m51.084s
sys	0m0.650s

Composer on HHVM:

$ time hhvm /usr/local/bin/composer update
...
real	0m15.132s
user	0m13.072s
sys	0m0.393s

The results speak for themselves. HHVM took only 28% of the time as compared to the PHP engine.

Installing HHVM on Mac OS X

I believe the best way to install HHVM on Mac is with Homebrew. In case you don’t have it installed yet, let’s start there.

Install Homebrew

$ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

Add additional required repositories to Homebrew for HHVM

$ brew tap homebrew/dupes
$ brew tap homebrew/versions
$ brew tap mcuadros/homebrew-hhvm

Install MySQL

Due to a bit of an issue with dependencies as of this writing I had to install MySQL before installing HHVM. You may not have this issue depending how long it takes to be repaired, but I suggest just installing MySQL up front just to be safe.

$ brew install mysql

Install HHVM

This is a long process (45+ minutes) and will take time to compile the various dependencies as well as HHVM itself. Grab a cup while you wait.

brew install hhvm

Default to running Composer with HHVM

While there’s a lot you can do with HHVM in the big picture, using it to run Composer is a great place to start. The best way to do this is to create an alias in your shell. Place the following in your .bash_profile to ensure it autoloads when Terminal starts.

$ alias composer='hhvm /usr/local/bin/composer'

The example above assumes you have installed Composer globally. If you have not, you will need to adjust your alias to something like below and run composer on the same directory level as your composer.phar file.

$ alias composer='hhvm composer.phar'

And that’s it! I hope this is helpful to you and if you find a better way please share in the comments.

Phil’s Whiskey List

November 20, 2013

The Spark

About a month back Phil Coffman put out a request on Twitter for whiskey recommendations and the response he got was sizable. All said he collected about 22 different bourbon, scotch, and whiskey recommendations. Now what to do with them or even how to chose what to try first…

I personally see a lot of these types of lists floating around for the “best” of anything and they are never really captured and shared which is a major bummer. Phil had the great idea to compile this list into a simple page on his site and to share his findings with others.

Enter The Developer

Phil mentioned he planned to continue to build out the list and style it up more extensively. It was suggested that he add ratings and other more dynamic features, but Phil wasn’t too sure on where to start. That’s where I came in.

That evening I set up a fresh install of Laravel and got to work. Here’s what we ended up with:

http://philswhiskeylist.com

The Tools

First and foremost, the site is build on Laravel 4, the new hotness on the PHP streets. I’ve fallen in love and will never look back. Sorry CodeIgniter!

I built the social login for Facebook and Twitter using the great HybridAuth library. I will note that I had some issues with the latest master branch and had to jump up to Version 3.0.0 to get things working as expected.

What’s Next?

While this won’t likely be the next hot app to be acquired by Facebook, Phil and I want to do a few things to make it even more useful. Features like sorting, maintaining your own list of whiskeys you’ve tasted, descriptions, and pricing ranges. More on that to come.

Have some other ideas? Drop a comment below or let Phil or me know on Twitter.

Pin Your OS X Dock to the Bottom Right

November 19, 2013

Link: http://thesweetsetup.com/os-x-dock-bottom-right/

A cool tip on how to pin your dock to the lower right hand corner of your screen. I really like this tip because it givse me that extra bit of real estate to not have it on the bottom, but it isn’t sucking into my full screen width either. Thanks Shawn!

While you’re there, check out Shawn’s new website, The Sweet Setup, for recommendations on all the best apps for iPhone, iPad, and Mac.

Sorting Algorithms Visualized

November 14, 2013

Link: http://kottke.org/13/11/sorting-algorithms-visualized

A very cool (and nerdy) video showing the process of running 15 different sorting algorithms. The video is accompanied by tones that vary based on the length of the bar being moved which results in a pretty cool and chaotic result.

Standing Desk Conversion

May 21, 2012

I built a topper this weekend to convert my sitting desk into a standing desk and it turned out to be really easy.

I’ve been interested in the idea of a standing desk since talking to Emily Smith and Charlie Pratt several months ago, both touting the improved level of energy and productivity they feel by standing. Having recently bought new desks at Bold, I just wasn’t ready to commit full-time to something I didn’t know how much I would like.

Enter the desk topper. For $30 in supplies and a few hours of work, this is the perfect solution. If I love it, it stays. If I hate it, it goes.

Day One has gone pretty well. I’ve got some tiredness in my feet and lower back, but nothing unbearable. I do feel a bit like I’m towering over everything around me, but at 6′ 5″ that’s not an entirely new feeling. Drowsiness is non-existant and all-in-all it’s been a productive day of work.

I plan to add a mounting bracket to secure the base of the iMac. It freaks me out too much having it nearly two feet off of the main desk.

I’ll check back in at the end of this week for an update on how it feels, any noticeable complications and/or unexpected upsides, and my decision on a plan for Week 2.

 

UPDATE: After a week of using the standing desk topper I’m still on board with it. There was definitely some fatigue through the week, but I think that had a lot to do with adjusting muscle groups. I notice I am a lot more alert and attribute that to the general fact that I’m standing and would collapse otherwise. I did notice that my legs and back became tired more quickly the day after a thorough night of volleyball the previous day. I expect that to become less of an issue as well in the days and weeks to follow. So far, so good!

Loading Environment-specific Configuration Files in CodeIgniter

May 17, 2012

About a year ago, CodeIgniter got the addition of an ENVIRONMENT constant which saved me a lot of headaches with managing difference between my various environments (development, staging, production).

// Conditional I add to index.php to self-determine the environment
if ($_SERVER['SERVER_NAME'] == 'mysite.dev')
{
	define('ENVIRONMENT', 'development');
}
else
{
	define('ENVIRONMENT', 'production');
}

if (defined('ENVIRONMENT'))
{
	switch (ENVIRONMENT)
	{
		case 'development':
			error_reporting(-1);
		break;
		case 'testing':
		case 'production':
			error_reporting(0);
		break;
		default:
			exit('The application environment is not set correctly.');
	}
}

Not only is it great for setting up server configurations like error reporting, it’s perfect for use in config files as well.

// Cloud asset bucket
switch (ENVIRONMENT) {
case 'development':
	$config['s3_bucket'] = 'mybucket_develop';
break;

case 'staging':
	$config['s3_bucket'] = 'mybucket_staging';
break;

case 'production':
default:
	$config['s3_bucket'] = 'mybucket_production';
break;
}

Instead of having to ignore configuration files in Git to handle the differences in production vs. development, now all that is necessary is a conditional to handle the variations.

Fast-forward a year, all the way to yesterday, and I happened upon another great little feature: “Environment-specific configuration files.” It was really by accident that I stumbled on it and only did because I was searching for ENVIRONMENT in my full CI project.

// Is the config file in the environment folder?
if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
{
	$file_path = APPPATH.'config/config.php';
}

What! So basically this is telling me that I can have a ‘development’ and ‘production’ folder inside of my ‘application/config’ folder and it will precede the main config.php file. Better yet, it works for all the config files (hooks, constants, routes and even libraries).

I headed to the CI docs and found one paragraph about environment-specific configuration files in the Config class docs. Not exactly prime real estate if you want to get noticed…

Since this was such a surprise to me, I figured it might be helpful to someone else as well. No more conditionals, no more Git ignores. Nice!

Greenville Grok

March 18, 2012

I’m new to the web conference scene. I’ve never been to SXSW, Brooklyn Beta, or the like, but there’s something about Grok that’s highly appealing. I continue to believe that CoWork is an anomaly in the web world and if you’re within driving range of Greenville, you’d be out of your mind to not rent a desk and join that fantastic community. So, knowing that this great group of folks was hosting a conference; how could I not sign up?

Grok isn’t just your typical conference where you can sit back and consume. You’re expected to be a part of the conversation, to contribute your thoughts and experiences, and even to lead the dialogue at times. “How crazy, I don’t have anything to add,” was my first thought. While I’m not the type to force my voice to be heard, I was able to add my perspective and even get some feedback on stuff we are working on at Bold. Thirty or so folks willing to provide their years of insight and experience on something our little 4-person shop is working on right now. Priceless!

But Grok is more than just a web conference, it’s a chance to meet your heroes, your Twitter friends, and to discover new, highly talented people you’ve never come into contact with before. On that note, I’m going to share some folks I’ve been wanting to meet for some time that I finally got to have conversations with this weekend as well as a few people I met for the first time and wish I had known for much longer.

People I’ve Wanted to Meet

  • Rogie King – What an awesome, solid guy. Not only does he knock out some of the best work I’ve seen, this guy cares for the community. Without even trying, so many are encouraged by his support, feedback, and passion. I could have used way more time with this guy and hope to find some in the future.
  • Joshua Blankenship – How could you say anything but good things about Joshua? I was really struck this week by his pure authenticity. Such a great thinker and leader. I’d work for this guy any day.
  • Chandler Van De Water - This guy bring the energy and the fun. There’s never a dull moment when Chandler is around (that is, unless he just spent three hours zip lining on little sleep). I want that beer app!
  • Emily Smith – I’ve actually know Emily for a while, but never gotten to have real conversation. I was lucky enough to have Emily as a travel buddy from SF and needless to say it turned the disaster that is airline travel into something great. Emily is top-notch at what she does, but is really well-rounded as well. I learned a ton about healthy eating and psychology. If you need IA/UX for a project, Emily is the first person you should contact.

People I Wish I’d Known Sooner

  • Tyler Sloan – “Mr. Southern Hospitality”. Tyler invited me into his home for the weekend without even knowing me and I think it’s part of what made Grok so great. He and his wife, Allie, were so fun to hangout with and chat. If you don’t know Tyler, you need to pronto.
  • Jeremy Jantz – I had several really great conversations with Jeremy. One of the nicest guys I met. I think we might be kindred spirits. I want to know beer like this guy!
  • David Stevens – Another all-star from Newspring. David and I talked after my 10/20 and gave me really great feedback about FRVNT, threw out a ton of ideas, and shared a lot about what he’s up to at Newspring. Really smart guy. I look forward to collaborating down the road.

Both lists could easily be significantly longer because I met so many great people. This is why we need to Grok. Let’s continue to make this community great, support one another, put faces to names, and continue to do the best work we can by supporting one another. Thank you to Matthew Smith and the CoWork folks for such a great event. I can’t imagine not being there next year!