Chris Loftus Code and stuff

Simple Way To Install Laravel Homestead For A PHP 5.6 Project

Simple Way To Install Laravel Homestead For A PHP 5.6 Project

If you’re running a recent version of Laravel Homestead (PHP 7) and you need to install an old Laravel app, in my case 5.0. You’ll run into difficulties as 5.0 is not compatible with PHP 7.

Here’s how to set up Laravel Homestead with PHP 5.6 for the project.

SSH into your current Homestead box and change the directory to the Laravel 5.0 project.

cd ~/Homestead
vagrant ssh
cd ~/Code/laravel50

Require Homestead v2.2.2 for the project. composer require --dev laravel/homestead 2.2.2

After it has installed, run the make command to generate the Vagrantfile and Homestead.yaml files.

php vendor/bin/homestead make

Once this is done, exit the SSH session and change directory to the project path on your host machine. Now boot the vagrant box:

vagrant up

This will download the v0.3.3 box and boot it.

You may see a warning message about using a password to execute a MySQL query on the command line. This might be because the MySQL password has expired.

SSH into the box and login to MySQL:

vagrant ssh
mysql -u homestead -p
secret
SET PASSWORD = 'secret';
exit

Then to complete the provisioning:

vagrant provision

This will run the remaining scripts, then you should be good to go!

How To Force Remember Me Login In Your Laravel 5 Application

Because no one likes being logged out, or having to check “Remember Me” when they login.

So, how do we make Laravel always keep a user logged in?

First of all we can get rid of the “remember” input on the login page (if you have one).

Secondly we need to take a look at how Laravel handles authentication. So we take a look in our AuthController.php.

Here we can see two references to AuthenticatesAndRegistersUsers:

<?php

use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;

class AuthController extends Controller {
    use AuthenticatesAndRegistersUsers, ThrottlesLogins;
    // ...
}

This must hold all of the authentication logic. So let’s check out the trait.

We can do this by navigating to the file.

vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesAndRegistersUsers.php

<?php

namespace Illuminate\Foundation\Auth;

trait AuthenticatesAndRegistersUsers
{
    use AuthenticatesUsers, RegistersUsers {
        AuthenticatesUsers::redirectPath insteadof RegistersUsers;
        AuthenticatesUsers::getGuard insteadof RegistersUsers;
    }
}

Here we can see that the AuthenticatesAndRegistersUsers trait includes another trait: AuthenticatesUsers. Open this file (it’s in the same namespace) and you will see the authentication logic.

As you scroll through the methods (which are in a logical order), you will see this one:

<?php

    /**
     * Handle a login request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        $throttles = $this->isUsingThrottlesLoginsTrait();

        if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        $credentials = $this->getCredentials($request);

        if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
            return $this->handleUserWasAuthenticated($request, $throttles);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        if ($throttles && ! $lockedOut) {
            $this->incrementLoginAttempts($request);
        }

        return $this->sendFailedLoginResponse($request);
    }

The attempt call is what we are interested in. It does this: “Attempt to authenticate a user using the given credentials.”

We pass it the user’s credentials and whether to remember the user’s session. It currently checks to see if the request has a ‘remember’ input.

However, we can simply change this to ‘true’, to always force “remember me”.

But we can’t make the change in this file, as it’s part of the framework. We have to overwrite this method in our AuthController. Copy the whole method to your AuthController and change it to force “remember me”.

<?php
if (Auth::guard($this->getGuard())->attempt($credentials, true) {
    return $this->handleUserWasAuthenticated($request, $throttles);
}

Now your Laravel application will always remember a user’s session, so they won’t have to login again. Unless they clear their cookies.

How To Disable Xdebug with PHP 7 CLI Ubuntu

How To Disable Xdebug with PHP 7 CLI Ubuntu

If you are running PHP 7 with Xdebug, or like me, use Laravel Homestead, you might have seen this error message:

You are running composer with xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug

And Composer will take an age to do anything.

To fix this, prior to PHP 7 people would suggest to comment out the extension from your php.ini file. However, in PHP 7 they are no longer in there.

Instead, we use the phpdismod command.

$ sudo phpdismod -s cli xdebug

The -s flag tells it to disable Xdebug for the CLI SAPI (/etc/php/7.0/cli) and not FPM.

And just like that, the warning message should be gone. No need to restart PHP.

Using npm, bootstrap-sass and gulp-ruby-sass 1.0.0-alpha

I’m using npm as my only package manager now, as all the packages I need from Bower are available on npm, so I don’t see why I should use both.

On a recent project, I had some trouble with gulp and gulp-ruby-sass 1.0.0-alpha.2. I previously installed gulp-ruby-sass with Bower, which used an older version.

The Packages

$ npm install gulp gulp-ruby-sass gulp-autoprefixer bootstrap-sass browser-sync --save-dev

After installing these packages with npm, I then created my gulpfile.js. It looked something like this:

var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefix = require('gulp-autoprefixer'),
    notify = require('gulp-notify'),
    browserSync = require('browser-sync'),
    reload = browserSync.reload
;

var config = {
    sassPath: './resources/sass'
};

gulp.task('sass', function() {
    return gulp.src(config.sassPath + '/style.scss')
        .pipe(sass({
            style: 'compressed',
            loadPath: [
                './resources/sass'
            ],
            // Unresolved bug with sourcemaps
            'sourcemap=none': true
        })
        	.on('error', notify.onError(function (error) {
				return 'Error: ' + error.message;
        	}))
        )
        .pipe(autoprefix('last 2 versions'))
        .pipe(gulp.dest('./public/css'))
        .pipe(reload({stream: true})) // BrowserSync
    ;
});

gulp.task('html', function() {
    return gulp.src('./public/*.html')
        .pipe(gulp.dest('./public'))
});

gulp.task('browser-sync', function() {
    browserSync({
        proxy: 'mlm.local'
    });
});

gulp.task('watch', function() {
    gulp.watch(config.sassPath + '/**/*.scss', ['sass']);
    gulp.watch('./public/*.html', ['html', reload]);
});

gulp.task('default', ['sass', 'browser-sync', 'watch']);

The Problem

After saving this and trying to compile my Sass, gulp was spitting out this error:

TypeError: Arguments to path.join must be strings

The Solution

It turns out that in gulp-ruby-sass 1.0.0 the syntax has changed a little. As subtly noted.

Now when creating a Sass gulp task, instead of:

gulp.task('sass', function() {
	return gulp.src(config.sassPath + '/style.scss')
		.pipe(sass({
			style: 'compressed'
			// etc...
		}))
})

You need to do:

gulp.task('sass', function() {
	return sass(config.sassPath + '/style.scss', {
		style: 'compressed',
		loadPaths: [
			'./node_modules/bootstrap-sass/assets/stylesheets'
		]
	})
		.on('error', function (err) {
			console.log('Error!', err.message);
        })
        .pipe( autoprefix('last 2 versions') )
        .pipe( gulp.dest('./public/stylesheets') )
        .pipe( reload( {stream: true} ) )
    ;
})

And it works. Note I haven’t added a js task, but its straightforward enough. I also need to investigate sourcemaps which there were issues with but I think they are fixed in 1.0.0-alpha.

I <3 Gulp! Here’s my current gulpfile.js.