Thursday, March 03, 2016

Enabling xdebug on the command line

Just a quick note to my future forgetful self, and other Mac and PhpStorm users:

To enable PHP xdebug to debug command line scripts, the simplest way is to enable the extension and setup the parameters when you invoke PHP on the command line. Doing that can be a bit verbose, so to do this nicely, setup an alias in .bash_profile or .bashrc  or .zhrc, like so:

Just make sure xdebug is installed, you're enabling the correct extension for your version of PHP, the remote_host is set to the IP of the machine you're running the script on, and that your listener (PhpStorm in my case) is listening to the same remote_port.

After you've set that up, if you want to see what other options you can enable, just run:
"phpx -i | grep xdebug"

Running xdebug-enabled PHP this way has the nice side-effect of only enabling xdebug when you need it, avoiding its effect on performance when you don't.

Of course your mileage on Windows may vary.

Saturday, January 30, 2016

Creating live links in Whoops (Laravel 5.1 edition)

Whoops is "an error handler framework for PHP. Out-of-the-box, it provides a pretty error interface that helps you debug your web projects, but at heart it's a simple yet powerful stacked error handling system." I was introduced to it in Laravel 4, but then it was removed in Laravel 5. Matt Stauffer and then Ryan Winchester provided instructions on bringing Whoops back into Laravel 5.x and it's much nicer than the standard Laravel error message.

Out-of-the-box, it also provides 'live' links into your code, directly to the file and line on which the error occurred, and all the way through the stack trace. Pick a point in the stack, click on the file link, and if you've set the editor properly in the Whoops handler, you're instantly in the correct spot in your code!

That is unless the error occurs on a server, and that server has a different base path than the machine where your code resides. A server running on a Vagrant box for instance. Like many other things, the server path has to be mapped to a local path. In the Whoops error handler, it needs to map to the correct local-to-your-editor file location so Whoops can build the correct links.

Here's the way to do that:

First follow Ryan's excellent instructions for getting Whoops running in Laravel 5.1. Then modify this area of his code:


To this:


And add a 'vagrant home' variable to .env:


In the new callback in handler.php:
  • line 12 adds a $translations array that rewrites the source file location from 'remote' to 'local' directories
  • line 15 performs the 'translations' and urlencodes the resulting location
  • line 19 sets the editor. This doesn't have to be Phpstorm by any means. Whoops PrettyPageHandler contains a list of editor links. The path for Sublime would be "subl://open?url=file://$file&line=$line" or MacVim: "mvim://open/?url=file://$file&line=$line"

Also fix the CSS

I wasn't entirely happy with some of the new Whoops 2.0 css, so I overwrote some of it in an alternate whoops.base.css file which has to be registered with Whoops, so:
  • line 24 adds another local-to-the-app resource path
  • line 25 adds the custom css
Which is just this:

The original Whoops 2.0 css lives in {doc_root}/vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.css

Tuesday, December 01, 2015

Switching database ports on-the-fly for Artisan, PHPUnit

One of the minor (really minor) annoyances of using Artisan in a Homestead/Vagrant environment is having to remember to run commands that interact with a database on the server, since that's where the database lives. It's possible to run them in the host environment, but you have to switch the host port to the correct forwarded port (from 3306 to 33060 for MySql).

A few extra properties in .env, and a wee bit of code in the not-often-used 'port' entry does that switching in the database configuration file based on the $_SERVER['HOME'] entry, which is completely passive and doesn't require any special setup on the server. Works for PHPUnit tests too:


This solution may be a little hacky, but it works reliably. If there's a better way (there probably is), please let me know in the comments.

Also note the change from the default 'utf8' in 'charset' and 'collation'. This has nothing to do with port switching but has everything to do with MySql's handling of UTF8. There's a good writeup about it here, the gist of which is:
MySQL’s utf8 encoding is awkwardly named, as it’s different from proper UTF-8 encoding. It doesn’t offer full Unicode support.
...
Luckily, MySQL 5.5.3 (released in early 2010) introduced a new encoding called utf8mb4 which maps to proper UTF-8 and thus fully supports Unicode...

So I (we) should have been using MySQL 5.5.3 with that charset for at least the last 5 years.

Tuesday, November 24, 2015

Testing a New Artisan command in Laravel 5.1

It took me quite a while to figure this out today (and for sure there may be a better way), but there didn't seem to be a well-documented way to test Laravel 5.1 Artisan commands. The main reason that I want to do this is to be able to run some simple commands directly in an Artisan command without writing another class just to essentially act as a test harness. In the case I was working on, I'm adding a field to a database table that needs to be populated with an initial attribute in every row for ElasticSearch. This will normally happen when a record is upserted, but initially it'll run once for each row in a loop as part of a multi-system update. I thought I'd run it as an Artisan command, although realistically it'd be better run as a queue-able job.

I spent some time with Laracasts but the TDD tests were 1) based on Codeception (nice, but not what I wanted) and 2) were for Laravel 4. Directly using the Symfony console test methodology doesn't work with Laravel's IoC container in Laravel 5.1. Even the Laravel foundation tests don't specifically test each of the Artisan console commands. At least I couldn't find anything, although ultimately it was the way that Laravel instantiates Artisan that gave me a clue.

You can run an Artisan command in your tests, but what I really wanted to do was check the output to the terminal, which means capturing stdout while running a command, which the test-native Artisan command doesn't support.

In any event, this works well, and displays both ways of running an Artisan command in a test:

A blog post every couple of years seems to be about the right frequency. No?

Thursday, May 09, 2013

Implementing Page Objects in Codeception


This a short tutorial that describes one way to implement Page Objects in Codeception. as described in the "Ruling the Swarm of Tests with Codeception" post by Michael Bodnarchuk.
 
The Page Object pattern in Codeception describes a way to represent a web page as a class and the DOM elements on that page as properties of that class. This allows you to use to access the page and its properties using the class description rather than the page itself and makes it much easier to create robust acceptance tests that aren't as dependent on the stability of the page itself.

By definition, each 'Page Under Test' will have a dedicated static class. This class can of course be extended for variations, such as the case where some of the page's properties can only be selected by their label and you need to test the page in French. Each class will have its own file in a directory dedicated to Page Objects from which they will be autoloaded as necessary.

Let's get started.

We'll assume that you already have Codeception installed, your tests bootstrapped and built, and that we're creating a 'cept' acceptance test.

First create a PageObjects directory that will hold your Page object classes in the Acceptance directory. It doesn't have to be located in that directory, it could be at a more global level or anywhere on your system but it's convenient if you're just using it for acceptance tests to have it there.

 $ mkdir tests/acceptance/PageObjects/  

Let's test the 'home' page. We'll call our class HomePage and create it as a class in the HomePage.php file.

 <?php //location: tests/acceptance/PageObjects/HomePage.php  
 class HomePage {  
 }  

Next we'll add some properties to test. We want to make sure the page has a title element, a body div, a login link, and that the title text contains 'Home'. So we're going to add public static selectors for those properties, a test value for the title text, and the page URL (in case it changes globally some day).

 <?php //location: tests/acceptance/PageObjects/HomePage.php  
 class HomePage {  
      public static $URL = '';  
      public static $titleText = "My Cool Site";  
      public static $titleElem = "h1";
      public static $bodyElem =  "div#body";  
      public static $loginLink = array("link" => "Login", "context" => "div#head");  
 }  

Classes can be loaded using an spl_autoloader, so lets add one and register it. We'll put this in an _autoloader.php file.

 <?php //location: tests/acceptance/_autoloader.php   
 spl_autoload_register(function ($className) {  
      foreach (array('PageObjects', 'Controllers') as $type) {  
           $filePath = __DIR__ . DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR . $className . '.php';  
                if (file_exists($filePath)) {  
                     include_once($filePath);
                     }}});  

... and then we'll simply require it in our acceptance tests _bootstrap.php. Since _bootstrap.php is run twice for every test, we need to make sure that we require our autoloader just once, or our classes will be declared twice.

 <?php //location: tests/acceptance/_bootstrap  
 // Here you can initialize variables that will for your tests  
 require_once "_autoloader.php";  

Now we need a 'cept file

 $ php codecept.phar generate:cept acceptance HomePage  
 Test was generated in HomePageCept.php  

And that's it! To use the class to test your page, just use the static class properties anywhere you would use a selector or test value.

 <?php //location: tests/acceptance/homePageCept.php 
 $I = new WebGuy($scenario); 
 $I->wantTo('check the basic contents of the home page'); 
 $I->amOnPage(HomePage::$URL);  
 $I->see(HomePage::$titleText);  
 $I->seeElement(HomePage::$titleElem);  
 $I->seeElement(HomePage::$bodyElem);  
 $I->click(HomePage::$loginLink['link'], HomePage::$loginLink['context']

Happy testing.

P.S. I'll be implementing the "Steps Controller" from the article, so there'll be another tutorial here. And I updated the crumby autoloader I had to something that works on case-sensitive file systems.

Friday, January 18, 2013

Laravel 4 dilemma


Like many folks in the +Laravel community, I’m struggling with whether to stop developing in Laravel 3 and switch to Laravel 4 now, rather than later. I’ve watched the Laravel 4 screencasts, read the ‘what's new and improved...’ blog posts and tutorials, lurked in the IRC channel, read the issues and related comments on GitHub, seen the questions and answers on StackOverflow, checked out the UserVoice suggestions, the Twitter feeds, the Laravel 4 forum and of course the excellent and ever-improving new docs. There’s a lot there to like, and fear. A lot to digest too.

I have a relatively heavy investment in both the time spent selecting Laravel 3 over other frameworks (which included deciding to stick with +PHP) and in learning L3 (not there yet). But I’m only a few weeks into putting together a Twitter Bootstrap, Backbone, Laravel v3 site, parts of which are behind schedule, that’s basically due in about 6 months.

I’d be happy to keep working in L3 if I thought that it would be easy to port a fairly sophisticated site (lots of bundles, lots of 3rd-party dependencies and integration) from L3 to L4, but as I see more people using the beta I’m becoming increasingly concerned about important parts of L3 that aren’t being carried over into L4 (bundles for instance), with no clear guarantee that they ever will be, as well as aspects of L4 that significantly differ (changes to routing and PSR-0 class names immediately come to mind) as well as other incompatibilities related to the switch to Composer, more reliance on Symfony components, and the increased use of IoC. Laravel 4 seems like a significant upgrade in both functionality and complexity, losing some of what made it more fun (and productive) in the first place.

It’s starting to look like it’s going to require a significant amount of work to port a L3 app to L4. It’s also looking like a lot of the work I’m currently doing in L3 is handled much more effectively in L4. For instance, the changes to routing make routing both easier (resource routes) and more sophisticated (regex). But ‘resource routes’ can’t currently be ‘named routes’, breaking named routing references. So can I use them? Not really, not without names. Will a naming convention be included at some point? Unclear -- and this is a problem.

I know L4 is currently just an early beta, but traditionally a beta version is expected to be feature-complete but buggy. I know that the trend is to release feature-incomplete alphas and call them betas, but it’s hard to reconcile this with a development framework on which I depend. I know too that L3 has had a somewhat rolling feature set and this has been a source of both praise and criticism. It’s seems that L4 is unlikely to lose features at this point, but it also seems likely that it will be some time before it stabilizes. I know that the Laravel developers are working their butts off and that some of what appears to be instability is just not yet documented. But I also see that some of the changes they’ve made in L4 may not stand up in the face of growing resistance from a rapidly expanding L3 user base — they don’t have the same freedom that +Taylor Otwell  had when he upgraded Laravel v2 to v3.

You see, I come to Laravel from +Symfony2, not CodeIgniter like so many who have embraced Laravel. I started working with Symfony around v0.8 and have some experience (mostly bad) working with a framework that changes significantly under my feet. For a while, the Symfony team helped by providing conversion scripts that made the bulk of the code changes required to move from release to release (there was still a lot of work), but these stopped working for me around v1.2 and I never did upgrade my older apps to v1.4. I stopped using Symfony entirely with v2 because it was pointless to port my oldest (and most stable) apps and it was actually easier to work without a framework for most of the work I was doing.

So it looks to me like Laravel is headed down the same road, and perhaps this is inevitable. My experience with Symfony pushes me to embrace L4 as soon as possible to minimize the amount of time spent working in a less-effective, but stable, older version that I eventually must abandon. But the current lack of stability in L4 keeps me where I am in L3. Meanwhile I focus on the frontend, setting up tests and stubbing out the backend, and flirting with other frameworks.

Just had to get that off my chest.


Sunday, February 20, 2011

This is worth remembering...

Paul Miller And The Five Rules Of Stunt Resignation
"... within three days of being fired as editor of a magazine I’d co-founded, I announced that I was launching a brand new company called The Friday Project. Of course I had absolutely no idea what The Friday Project would do, but I registered the domain name and created a holding site and sent out a press release anyway. Eight months later, when my new business partner and I finally revealed that The Friday Project would be a new publishing house, everyone assumed we’d planned it that way from the start. Appearances are everything."