Laravel Eloquent gotcha using With and Find

The Eloquent ORM in Laravel makes it easy to pull in related models using the ::with() method.  It’s very useful and can solve the N+1 Query problem that can occur when accessing related models in a loop from the parents records.

<?php
$data = MyParentModel->with('ChildModel');

You’d commonly want to use this when accessing a particular parent model using the ::find() or ::findOrFail() method. The trap can be that with() must be called before findOrFail().

If you chain methods and call findOrFail() first it will be ignored and your result set will include all parent rows!

<?php
$data = MyParentModel->with('ChildModel')->findOrFail($parent_id);

WordPress Debugging

Bronson Quick spoke at the WordCamp Sunshine Coast today on debugging for WordPress. He covered techniques for fixing a white-screen of death as well as getting detailed information to sort out squirrelly bugs and performance issues.

Firstly WordPress has a few rad constants you can switch on to get better information about where things are breaking.

define( 'WP_DEBUG', true );     //I was blind, now I can see (my PHP errors)
define( 'WP_DEBUG_LOG', true ); //for production, write logs to wp-content
define( 'SCRIPT_DEBUG', true ); //use non-minified versions of core CSS/JS
define( 'SAVEQUERIES', true );  //log queries, look for suspicious ones. Not for production

Local Development

Develop in an environment close to the production hosting environment your site will be deployed to. The best way to do this is with virtual machines and tools like Vagrant.

Chassis is a WordPress focused VM for Vagrant. It’s configured with Nginx, MySQL, PHP 5.4 – 5.6 and has a bunch of handy extensions available to set up things like Xdebug, Debug Bar and Query Monitor quickly. The disposable nature of VMs means you can create one for each project.

Creating a Chassis VM

git clone git@github.com:Chassis/Chassis.git myproject
cd myproject
vagrant up

Chassis Extensions

Debug Bar gives you a lot of insight into what WordPress is doing to generate a page.

cd myproject/extensions
git clone https://github.com/Chassis/Debugging.git
vagrant provision

This will install a collection of Debug Bar plugins into WordPress en mass. What a time saver.

Query Monitor is an alternative tool for monitoring database activity in WordPress. It does more than monitoring SQL and can even show script dependencies, en queued styles and highlight errors.

So…

  • Develop in an environment similar to where you’ll deploy. Let Chassis set that up for you.
  • Use Xdebug, Debug Bar and Query Monitor as necessary to get insight into what your code is doing

Parse Amazon S3 Logs with PHP

Amazon let’s you turn on logging for S3 buckets to capture (lots) of information on what’s happening there.

I wrote a PHP script to download those log files and parse the HTTP GET requests into a database for easier analysis. The data could also be sent to another source if you preferred.

S3logs-php on Github

Example Usage:


<?php
require 'vendor/Autoload.php';

$cfg = require 'config/config.php';

$logs = new \S3LP\Logs( $cfg['aws'], 'logs/', 'storage/logs/' );
try {
  $files = $logs->download();
} catch(Exception $e) {
  exit( $e->getMessage() );
}

//Parse logs to array
try {
  $data = $logs->parseLogs($files, 'DELETE');
  if(!$data) {
    exit('No GET requests found in logs');
  }
} catch(Exception $e) {
  exit( $e->getMessage() );
}

//Save to DB
try {
  $db = new \S3LP\Db( $cfg['pdo'] );
  $inserts = $db->insert($data);

  echo "Inserted $inserts rows";
} catch(Exception $e) {
  exit( $e->getMessage() );
}

Get the code on Github.

wkhtmltopdf 0.12 on Ubuntu 14.04

The Problem

wkhtmltopdf is a library for rendering PDFs from HTML or live web pages.

  • apt-get install wkhtmltopdf  will install the older 0.9 version, which isn’t compatible with the Snappy PHP wrapper
  • wkhtmltopdf 0.9 is also unable to render on ‘headless’ operating systems and needs another package to simulate a display. The newer 0.12 version doesn’t have this problem.

The Solution

Manually Install the ‘Static’ Binary from wkhtmltopdf.org

(NB: If you’re not a root or super user most commands will need to be sudo…)

Download the Ubuntu “Trusty” build.
At the time of writing this is wkhtmltox-0.12.2.1_linux-trusty-amd64.deb

wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.2.1/wkhtmltox-0.12.2.1_linux-trusty-amd64.deb

Rename it something easy to type like wkhtml.deb

Extract it with this command

ar x wkhtml.deb
# if ar not installed run this:
# apt-get install binutils

Extract the binary

tar xf data.tar.xz

Move the binary file to /usr/bin

mv wkhtmltopdf /usr/bin/wkhtmltopdf

Now PDF Rendering Should Work

wkhtmltopdf http://example.com myTest.pdf

Laravel 5 Environment Config

Laravel 4 used a function that checked the servers hostname to determine the environment. Laravel 5 simplifies environment detection by having a .env file present in your project root.

.env.example is ignored by Laravel’s detection. You can fill it with the keys your application expects to act an an example for your own file.

.env is for the current environment

Add .env to your .gitignore file. It’s got to stay out of your repo so you don’t overwrite it each time you pull.
Copy/Rename .env.example to .env for each environment.

set the APP_ENV value within your .env file to tell Laravel where it’s running.

APP_ENV=local
APP_DEBUG=true
APP_KEY=123abc...
$app->environment(); //get the current environment
if($app->environment('local', 'staging')) { }  //test if local or staging env

You can retrieve your .env config values with the env() function.


$cfgValue = env('MY_SWEETAS_VARIABLE');

Detecting Environment in Laravel 4

Update: How to Get Environment in Laravel 5

Your PHP application should have different settings for its development and production environments. Here’s how you can set your Laravel 4 app to detect the environment, load the appropriate settings and keep installation-specific things like database credentials out of your Git repo.

Detecting The Environment

Laravel lets you provide arrays of hostnames it will check the server against to determine the environment.

Open bootstrap/start.php

$env = $app->detectEnvironment([
   'local' => ['MyMachineName', 'AnotherDevMachine'],
   'staging' => ['StagingEnvName']
]);

If unsure, use PHP’s gethostname() function to find your machine names.
This is the value to use inside the local/staging arrays

Laravel will default to ‘production’ if no other environment is matched.

 

Setting Environment Config Values

Laravel looks for .env.*.php files in the root directory (beside your composer.json and .gitignore files).

You will want to exclude these files from your Git repo. Add the following lines to your .gitignore

.env.*.php
.env.php

Then create an env file for each of your environments. Use .env.php for the production environment.
They should look something like this:

<?php

/**
 * Local Development
 */
 return array(
	'app.env'		=> 'dev',
	'app.debug'		=> true,
	'app.url'		=> 'http://example.dev',

	'mysql.host'	 => '127.0.0.1',
	'mysql.database' => 'bestDbEva',
	'mysql.username' => 'me',
	'mysql.password' => 'myTremendousPassword'

 );

The actual values are up to you. You can store whatever values you need within the application.

Using The Environment Values

Laravel config can now call getenv() to get the dynamic environment variable. For your DB config open app/config/database.php

'mysql' => array(
	'driver'    => 'mysql',
	'host'      => getenv('mysql.host'),
	'database'  => getenv('mysql.database'),
	'username'  => getenv('mysql.username'),
	'password'  => getenv('mysql.password'),
	'charset'   => 'utf8',
	'collation' => 'utf8_unicode_ci',
	'prefix'    => '',
),

6 SEO Tips for Web Designers

It’s a common conundrum in the web world. A designer puts a beautiful website together that the client is absolutely rapt with and hands it to the SEO to get it ranking who sheepishly tells them that it needs a bunch of changes. It’s almost like pretty sites just aren’t rankable sites. Well fortunately that’s not the case. Joe from Orange Digital has put together a list of helpful hints to ensure that your pretty website is still as SEO friendly as any.

1. Web Fonts are Your Best Friend

There’s nothing worse than being handed a website that has no crawlable information. If everything is displayed in images the Google bot (and others) can’t read it. Your amazing design is virtually unrankable. Web Fonts By using a combination of CSS, HTML and web fonts you can almost always reproduce the same effect that you get by displaying information with an image. Not only will your content be crawlable, but it will also be able to be marked up with metadata, meaning your awesome header graphic could also be the H1. If it were an image that wouldn’t be the case. Furthermore if you create a graphic using this method as opposed to an image, editing it is a cinch. If you want to change the text, colour, size or any other styling, you don’t have to pull the graphic back into Photoshop to change.

2. Copy Is Important

Accessible Copywriting Those minimalist highly visual, low word count designs might look great, but for SEO purposes they are incredibly counterproductive. Google needs content to work out what the website is about. Sure your metadata does some of the job but Google is a completionist and good copy indicates digestible information for the end user. Google’s algorithm is all about sending their users to results they can trust. If you want to retain the minimalist approach then the solution could be to hide the copy behind mouse-overs, however it may be worth questioning whether doing this pits aesthetics against usability.

3. Assume the Need For Drop Down Menus

The amount of times that I as an SEO have come across a WordPress site that doesn’t have properly designed drop down menus (or worse still doesn’t have them at all) is absurd. It’s a WordPress default function! The first live version of the website may not need them but just assume that down the line they will be needed and include them please. Drop down menus are an important part of site architecture from an SEO purpose as it allows you to internally link in a way that looks good and is natural, and the trends with design right now leaves no choice for SEOs but to create internal landing pages to rank. We need Google to be able to access them from other parts of the website and the top menu is the best place for it because…

4. Google Reads Like A Person

That means it reads from left to right and top down. The information that is higher on the page is assumed to be more relevant. If there is no crawlable information anywhere near the top of your page, the information that is crawled is assumed to be not important enough to show your users immediately. So that means that if you build a website that you have to scroll to before you get to the first part of the copy, the copy is SEO weak. At least try to include some crawlable information high on the page.

5. Ajax Content IS Crawlable

There once was a time when Ajax content was difficult, and in some cases impossible to crawl. Thankfully Google figured it out. It does involve tweaking. You can read more about the process here.

6. Consider Your SEO Friends

It’s basically just something to live by. If the website you’re designing has even the potential to ever need SEO, do right by your client and yourself by considering future need for SEO. Don’t just assume because it’s not your concern that it’s not a concern at all and never will be.

Joe McCord Joe McCord on Google+. Joe McCord on Twitter.