Using user-defined MySQL variables in Laravel

I attempted to do the following in Laravel:

DB::query("SET @rank:=0; UPDATE scores SET rank=@rank:=@rank+1 WHERE game_id=4 ORDER BY score DESC");

That is valid MySQL code, and works if you type it directly into MySQL via the command line, but Laravel was throwing an error:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL 
syntax; check the manual that corresponds to your MySQL server version for the right 
syntax to use near 'UPDATE scores SET rank=@rank:=@rank+1 WHERE game_id=4 ORDER BY' at line 1

SQL: SET @rank:=0; UPDATE scores SET rank=@rank:=@rank+1 WHERE game_id=4 ORDER BY score DESC

Bindings: array (
)

I attempted to separate the two queries:

DB::query("SET @rank:=0");
DB::query("UPDATE scores SET rank=@rank:=@rank+1 WHERE game_id=4 ORDER BY score DESC");

But Laravel still threw an error:

Method [] is not defined on the Query class.

DB::raw() to the rescue!

Solution:

DB::query(DB::raw("SET @rank:=0"));
DB::query("UPDATE scores SET rank=@rank:=@rank+1 WHERE game_id=4 ORDER BY score DESC");

"General error: 1005 Can't create table" using Laravel

If you're getting the following error when attempting to run a migration, you might be trying to add a foreign key on a parent field that doesn't exist yet.

SQLSTATE[HY000]: General error: 1005 Can't create table 'posts.#sql-XXXX' (errno: 150)

SQL: ALTER TABLE `comments` ADD CONSTRAINT comments_post_id_foreign FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE cascade ON UPDATE cascade

In the above example migration, the comments table is being created before the posts table, and a foreign key that references the id field in the posts table is attempting to be added. But since the posts table doesn't exist yet, it's resulting in an error.

Solution: Make sure the Schema::create() calls are in the right order, i.e. Schema::create('posts') has to come before Schema::create('comments').

Schema::create('posts', function($table) {
    $table->increments('id');
    ...
});

Schema::create('comments', function($table) {
    $table->increments('id');
    $table->integer('post_id')->unsigned()->index();
    ...
    $table->foreign('post_id')->references('id')->on('posts')->on_update('cascade')->on_delete('cascade');
});

If your Schema::create() calls are in separate migration files, you just need to change the order in which the files are processed during the migration. To do so, change the timestamp values in the names of the migration files so that the files get run in the correct chronological order.

2013_04_14_233507_create_posts.php
2013_04_14_233508_create_comments.php

Then, when you run php artisan migrate, the create_posts migration file will be processed before the create_comments migration file.

Laravel routes not working? Make sure .htaccess is working.

If your Laravel routes aren't working, and you're getting "Not Found" errors whenever you try and load a page, your .htaccess file is likely lacking permission to do its duty.

The key is the apache AllowOverride directive.

If you don't have AllowOverride set to All, your Laravel .htaccess file (/public/.htaccess) won't be able to enable mod_rewrite, and your routes won't work.

The first step is to open your apache httpd.conf file. In OS X, it is located at:

/private/etc/apache2/httpd.conf

Option 1) Modify your main <Directory> directive

This will change the AllowOverride value for all your websites. In your httpd.conf file, look for the main <Directory> directive:

<Directory "/var/www/html">
    ...
    AllowOverride None
    ...
</Directory>

Simply change it to this:

<Directory "/var/www/html">
    ...
    AllowOverride All
    ...
</Directory>

Option 2) Add a <Directory> directive to your site's <VirtualHost> directive.

<VirtualHost 127.0.0.1:80>
    DocumentRoot "/var/www/html/epigroove/public"
    ...
    <Directory "/var/www/html/epigroove/public">
        AllowOverride All
    </Directory>
</VirtualHost>

Save the changes to your httpd.conf file, restart or reload apache, and your routes should be up-and-running.

PHP Undefined index: extension

If you ever get the PHP error Undefined index: extension, it's most likely because a filename that has no extension is being passed to the pathinfo() function.

Example:

$filename = "/images/company_logo";
$parts = pathinfo($filename);
echo $parts['extension'];

Result:

Undefined index: extension

The filename must contain an extension, because pathinfo() gets the extension from the name of the file, not from the file itself. The file doesn't even have to exist; pathinfo() doesn't care.

Working example:

$filename = "/images/company_logo.png";
$parts = pathinfo($filename);
echo $parts['extension'];

Result:

png

GoDaddy, mod_rewrite, and Preview DNS

WARNING: Most mod_rewrite rules do not work when previewing a site hosted on GoDaddy.com!

If you are testing out a website using GoDaddy's "Preview DNS" feature (e.g. http://domain.com.previewdns.com/), do not expect mod_rewrite rules in your .htaccess file to work. I could only get very basic catch-all rules to work. All other rules resulted in 404 errors.

After much frustration, a GoDaddy representative confirmed what I suspected:

"The mod_rewrite is able to function on the hosting plan. However, due to the dependency of the URL, for the rewrite to function, the Preview DNS may not allow it to function properly. If the rewrite is coded properly then it will function once the website is made fully live through our hosting plan."

So I guess the solution is to cross your fingers and hope that your rules are set up correctly.

I hope this saves someone else a headache.

Use PHP to count number of files in a directory

Here's a simple bit of PHP code to get the total number of files in a directory using the glob() and count() functions:

$num_files = count(glob($_SERVER['DOCUMENT_ROOT'].'/path/to/directory/*'));

Or here's how to only count files with a .jpg extension:

$num_files = count(glob($_SERVER['DOCUMENT_ROOT'].'/path/to/directory/*.jpg'));

How to kill all MySQL sleeping processes

If you need to kill all sleeping processes in MySQL, here's a quick 'n' easy PHP solution:

$result = mysql_query("SHOW processlist");
while ($myrow = mysql_fetch_assoc($result)) {
	if ($myrow['Command'] == "Sleep") {
		mysql_query("KILL {$myrow['Id']}");
	}
}

HTML5 audio not playing in Firefox? Use OGG.

If you're attempting to play sounds using the new HTML5

If you're a Mac user, download the XiphQT Quicktime component. It will let you export sound files as .ogg files using Quicktime Player 7 (located in your Utilities folder).

Remove the default padding from a jQuery UI dialog

If you find the default padding on jQuery UI dialogs to be as annoying as I do, here's how you can remove it.

Make sure the follow style loads after the jQuery UI stylesheet has loaded, and it will override the default padding:

.ui-dialog .ui-dialog-content {
    padding: 0;
}

I like to have my sites' main stylesheet load after the jQuery UI stylesheet, so that I can include any jQuery UI overrides in it.

Toggle a MySQL field between 0 and 1

Here's a simple example of how to toggle an integer (most often a tinyint in my case) field in MySQL between 0 and 1:

UPDATE table SET int_field=MOD(int_field+1,2) WHERE id=123