Web Developer at Freelance

West Palm

Hire Me

Member Since 4 Years Ago

Experience Points 19,580
Lessons Completed 214
Best Reply Awards 2
Best Answer
  • Start Your Engines Achievement

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • First Thousand Achievement

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • One Year Member Achievement

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • Two Year Member Achievement

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • Three Year Member Achievement

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • Four Year Member Achievement

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • Five Year Member Achievement

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • School In Session Achievement

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • Welcome To The Community Achievement

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • Full Time Learner Achievement

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • Pay It Forward Achievement

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • Subscriber Achievement


    Earned if you are a paying Laracasts subscriber.

  • Lifer Achievement


    Earned if you have a lifetime subscription to Laracasts.

  • Laracasts Evangelist Achievement

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • Chatty Cathy Achievement

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • Laracasts Veteran Achievement

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • Ten Thousand Strong Achievement

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • Laracasts Master Achievement

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • Laracasts Tutor Achievement

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • Laracasts Sensei Achievement

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • Top 50 Achievement

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

17 Dec
1 month ago

timgavin left a reply on Add A End Date Automatically

@realrandyallen Thanks, this is exactly what I was looking for!

timgavin started a new conversation Add A End Date Automatically

I have a field that is a dateTime called start_at. I'd like to be able to automatically insert a dateTime value into an end_at field that is exactly one hour later than the start_at field.

DateTime::make('Start At')->rules('required'),

Is this possible? If so, how?

16 Dec
1 month ago

timgavin left a reply on Timezone Conversion

@kyYou're probably right; I was most likely thinking about this in the wrong way.

I have a calendar that is to be used by people globally. On this calendar a user can reserve a 1 hour block of time, and that hour can only have two users reserve it.

Currently, when selecting a start time, say 4:00 PM EST, the HTML value for the start time is 2018-12-16 16:00:00. Well, this gets entered as such in mySQL and then when I come back and view the page it's showing the block of time reserved is 1:00 PM because of the timezone offset.

So I guess I'm having a hard time figuring out what I need to do. My guess right now is to show 4:00 PM to the user, but have the HTML value be the offset time of 1:00 PM. Not sure how to do that though, but that's my current guess...

timgavin started a new conversation Timezone Conversion

When inserting a date into a table, how do I offset for the user's timezone using Carbon?

I'm trying different variations of the following, but can't get them to work. I either receive errors, or it just goes into the db as 2018-12-16 16:00:00 with no offset.

'start_at' => Carbon::parse('2018-12-16 16:00:00', auth()->user()->timezone),
14 Dec
1 month ago

timgavin left a reply on Pagination Is Over Http Instead Of Https

@realrandyallen As I mentioned in my post, I've already done that with URL::forceScheme('https'); :)

timgavin started a new conversation Pagination Is Over Http Instead Of Https

When paginating using {{ $posts->links() }}, Laravel is displaying the links as http:// instead of https://, even though I've specified https in the APP_URL inside .env, have set up URL::forceScheme('https'); in AppServiceProvider.php and am using SSL certs, not only from CloudFlare (using FULL), but have also installed a cert on the load balancer and am using LetsEncrypt on each server via Forge.

What could the issue be?

09 Nov
2 months ago

timgavin left a reply on Method Not Allowed For A Route That Doesn't Even Exist

Never mind, I understand why I'm receiving the method not allowed error. Brain fart on my part. it's been a while since I worked with Laravel. :)

Still doesn't explain why google is indexing it. weird.

timgavin left a reply on Method Not Allowed For A Route That Doesn't Even Exist

Why wouldn't I see a 404 when going to a non-existent URL?

I've searched my entire project, it's no anywhere else.

I've now started looking into other URLs that should be POST or DELETE only and accessing them via GET and I'm receiving that exception instead of a 404.

timgavin left a reply on Method Not Allowed For A Route That Doesn't Even Exist

I'm going to that route directly in my browser and receiving the MethodNotAllowedHttpException exception.

timgavin started a new conversation Method Not Allowed For A Route That Doesn't Even Exist

I have a POST route that is only accessible if a user is logged in:

Route::post(/'do/update', '[email protected]');

However, Google Search Console is showing a crawl anomaly for /do/update using GET. So I tested this, and when accessing that url via GET, I receive an MethodNotAllowedHttpException exception.

How is this even possible? There isn't a route set up via GET for /do/update - AND everything under /do is protected via middleware.

timgavin started a new conversation Security In Routes

I'm curious what's the best practice for stacking rules in routes/web.php?

Do I put the route first, then the security rules?

Route::group(['prefix' => 'account'], function () {
    Route::group(['middleware' => ['role:user]], function () {

Or the security role, then the route?

Route::group(['middleware' => ['role:user]], function () {
    Route::group(['prefix' => 'account'], function () {

Or does it not even matter?

16 May
8 months ago

timgavin left a reply on 1 Laravel Installation With 2 TLDs

Thanks to @campo and @cronix I got it all figured out; hope this helps someone else.

As @campo suggested, I added my subdomain to Cloudflare but just turned off protection.

In my .env file I had to put quotes around the value. Omitting quotes not only made it so I couldn't login to the site, but it also broke Envoyer's .env decryption!


In my Routes file I added another route to redirect all GET traffic back to the original site, and added the POST route to handle the uploads.

Route::group(['domain' => 'upload.mysite.com'], function () {
    Route::get('/', function () {
        return redirect(url('https://mysite.com'));
    Route::group(['middleware' => ['role:user|admin,post']], function () {
        Route::post('files', '[email protected]')->middleware('throttle:4,1');

And in my form I just added the URL

<form action="https://upload.mysite.com">
15 May
8 months ago

timgavin left a reply on 1 Laravel Installation With 2 TLDs

Unfortunately, when updating the .env and adding SESSION_DOMAIN=.mysite.com, then clearing my browser cache and cookies, I'm no longer able to login.

timgavin left a reply on 1 Laravel Installation With 2 TLDs

@campo I believe what's happening is that when the app goes to the upload subdomain, the currently logged in user's session is not being transferred to the route. Don't really know how to fix this though.

timgavin left a reply on 1 Laravel Installation With 2 TLDs

if I add Route::get('/', '[email protected]'); back in, and go to that route, I'm redirected to the login page.

timgavin left a reply on 1 Laravel Installation With 2 TLDs

The form is not located on the GET route. I decided against that as it didn't seem necessary since I'm only concerned with the uploaded file.

Should it be on the GET route?

BTW, I removed Route::get('/', '[email protected]'); from the route group as well, so there shouldn't be any conflicts.

timgavin left a reply on 1 Laravel Installation With 2 TLDs

I'm receiving a "this page timed out due to inactivity" error from Laravel. So I'm guessing it might be a CSRF issue? I do have the token on the form, and everything works perfectly up until I change the URL to upload.mysite.com.

After the file is uploaded, it's supposed to redirect to /home, instead it goes back to the form URL and shows the error message.

Oh, and I do have a Let's Encrypt cert on the subdomain, so https isn't an issue.

timgavin left a reply on 1 Laravel Installation With 2 TLDs

Well that makes sense!

I've tried it now, and it's still not working properly.

Here are my current routes for uploading

Route::group(['prefix' => 'files'], function () {
    Route::get('/', '[email protected]');
    Route::post('/', '[email protected]')->middleware('throttle:4,1');

and here's what I've changed it to

Route::domain('upload.mysite.com')->group(function () {
    Route::group(['prefix' => 'files'], function () {
        Route::get('/', '[email protected]');
        Route::post('/', '[email protected]')->middleware('throttle:4,1');

Do I need to put ALL of my other routes in a separate Route::domain function as well? If so, what would I call it?

timgavin left a reply on 1 Laravel Installation With 2 TLDs

@campo I already tried that, it wouldn't resolve unless it went through Cloudflare.

I had set up the subdomain, and it was working fine, so long as I had it listed in the Cloudflare CP. Once I deleted the record from Cloudflare I could no longer access it in my browser.

Perhaps I did something wrong?

timgavin started a new conversation 1 Laravel Installation With 2 TLDs

I'm allowing my customers to upload large files. Because I'm using Cloudflare, anything over 100 MB gets rejected, which is no good.

So what I'm thinking of doing is switching the upload form action from mysite.com/upload to mysite.net/upload. This way I'm using a domain name that isn't going through Cloudflare, so file sizes won't be restricted.

I've set up mysite.net as a site in Forge to mirror mysite.com by setting the root location in nginx to point to the current folder of mysite.com. So now when someone goes to mysite.net they see the contents of mysite.com.

Unfortunately, mysite.net is now open to DDOS attacks because it isn't running through Cloudflare.

So what I'd like to do is make it so that mysite.net/upload is the only route that's open under that domain, and that it's only accessible from my load balanced servers.

Is this possible, and if so: how do I do it?

I've been researching this and haven't really come across an answer that applies to me, the most common scenario is using subdomains, which is not applicable in my situation.

10 May
8 months ago

timgavin left a reply on 413 Request Entity Too Large (Cloudflare)

@Cronix Brilliant! Ok, so one thing I didn't mention is that I'm using a load balancer on Forge/DigitalOcean. I can set up the subdomain to point to the load balancer, but I'm curious on setting up the sub domain on the two app servers to point to the app's current directory.

Would I create a new site in Forge and add the subdomain as the URL, then edit the nginx conf file and point the root to the main site?

timgavin started a new conversation 413 Request Entity Too Large (Cloudflare)

I'm allowing large file uploads in my Laravel app, and am using Cloudflare. One of my customers told me today that they were unable to upload a 150 MB file and received a 413 Request Entity too Large error. I looked into this and it's actually coming from Cloudflare; they won't allow uploads greater than 100 MB unless you pay through the nose.

Cloudflare suggests that I create a subdomain that isn't tracked by them and upload through that.

My question: how would I do this in Laravel?

I'm using Spatie's Media Library and uploading to the site on which Laravel is installed; how do I use a subdomain within the app?

30 Mar
9 months ago

timgavin started a new conversation Block A State From Accessing A Route

I looked into Laravel Firewall, which will allow you to block access to routes by IP or country, but I'm wondering if there's a way to block by state?

For instance, say I want to block access to everyone in Florida from visiting my /I-hate-florida/ route.

Is this possible?

03 Mar
10 months ago

timgavin started a new conversation Search Multiple Fields In Same Table

I have a table which holds a user's statistics, such as age, height, weight, etc.

| user_stats  |
| ------------- |
| birthday  | date  | 2000-01-01 |
| height  | varchar  | 6.0 |
| weight | varchar | 200 |

Using Scout and Algolia, I want a user to be able to search for all of these attributes, and return only users that match.

In my form, I'm using <select> menus to display the search options, such as...

<select name="age">
    <option" value="20-30">20-30</option>
    <option value="31-40">31-40</option>

So, if a user wanted to find people who were 17 years old, 6' tall and 200 lbs., how would I go about doing this in my controller?

28 Feb
10 months ago

timgavin left a reply on Download Large File From S3 *kind Of* Working

@ohffs , you pointed me in the right direction.

I feel like an idiot. I had a .download class on the link, which triggered javascript that had implemented e.preventDefault(). Removing the class fixed it.

Thanks. :)

timgavin started a new conversation Download Large File From S3 *kind Of* Working

My authenticated users are able to download large files, so I've created a route that will initiate the download, located at: /download/post_id

The user clicks a button with a link to the route...

<a href="{{ url('download/'.$post->id) }}">
    <button class="btn btn-primary">
        Download File

The controller then fetches the post media and forces a download from S3.

The mechanics of this are working, the file will download, but NOT when the button is clicked. The only way I can actually get it to download is to right-click on the button and choose "save linked file as..."

When clicking the button, the button just highlights and stays that way; nothing happens. Nothing is downloaded. Why?

What's the best way to force download a large file via button click?

18 Feb
11 months ago

timgavin left a reply on Mix Compile Issue

@kreierson : Before

<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>

timgavin started a new conversation Mix Compile Issue

I'm not trying to do anything fancy, just add these files to a vendor.js file. Mix compiles just fine, but then Chrome gives me an Uncaught ReferenceError: swal is not defined.

If I add Sweet Alert via CDN everything works as expected, but compiling the files using Mix breaks the alert.

I can even see the sweet alert code inside vendor.js! So weird! What am I doing wrong?

], 'public/js/vendor.js');
03 Feb
11 months ago

timgavin started a new conversation Notification Inside MySQL Transaction

I'm working on a shopping cart and need to throw an exception if the user has insufficient funds in their account. I'd also like to notify them via email and database.

$user->notify(new InsufficientFunds($amount));
throw new InsufficientFunds;

Notification via email works fine, but not by database. I'm assuming this is because the code I'm using is wrapped in a transaction, so the database notification gets wiped out.

I've implemented ShouldQueue in my notification class, but it's still not persisting. Would this be because my local development environment is using sync as the queue method?

What would be a good solution to persisting a notification if it's in a transaction?

26 Jan
11 months ago

timgavin left a reply on Symnlink To External Disk

Okay, so what had actually happened was that my local symlink had been uploaded during the deployment, overwriting the symlink in the public directory.

Added the local symlink to .gitignore and problem solved.

timgavin started a new conversation Symnlink To External Disk

My DigitalOcean server has a volume attached for storing media, it's available at /mnt/media

I want my file uploads to be stored on the volume, and available in the view at /media/filename.jpg.

I've tried creating a symlink in the public directory, which points to /mnt/media but it's not working correctly; keeps telling me it's not available. I'm thinking maybe this gets corrupted during a deployment?

I tried creating the symlink in Envoyer, using the Manage Linked Folders option, but it appears I can only add folders which are relative to the public and storage directories. It doesn't look like I can do absolute links.

Any thoughts on how I can do this?

16 Jan
1 year ago

timgavin left a reply on Abort() Results In 500 Error

I should have clarified, I'm using abort(404). Sorry.

timgavin started a new conversation Abort() Results In 500 Error

Anytime I use abort() my app throws a 500 error.

This is on my iMac using Valet and Laravel 5.5.

I've tried chmod -R 777 /Users/tim/Sites/myapp/storage to no avail, and even went as far as sudo chmod -R 777 /Users/tim/Sites/myapp with no luck.

I know my code is working , because if I swap out abort() for dd('hello') it prints hello to the browser.

Any ideas?

07 Jan
1 year ago

timgavin left a reply on Eloquent Query Showing Wrong Result

Figured it out

->whereRaw('(category IN (1,2,3) OR category IS NULL)')

timgavin started a new conversation Eloquent Query Showing Wrong Result

I'm at a loss here.

I have different statuses on a post: published, draft, etc. My query should only select published posts; on my development server it's working correctly, yet on my production server it's showing posts with a status of draft and I can't figure out why.

Is it because the published_at field is not NULL for that particular post, and latest('published_at') is overriding ->where('status', 'published')?

$posts = Post::latest('published_at')
    ->whereHas('user', function ($query) {
        $query->where('status', 'active');
    ->when(auth()->check(), function ($query) {
        $query->whereIn('category', defaultCategories());
        $query->orWhere(function ($query) {
    ->when(auth()->guest(), function ($query) {
        $query->whereIn('category', defaultCategories());
    ->where('status', 'published')
    ->with('user.profile', 'pinned', 'comments', 'likes', 'tags')
06 Jan
1 year ago

timgavin started a new conversation Error: Cannot Find Module 'laravel-elixir'

I'm having a hell of a time with Gulp lately.

I was receiving this error before, so I ran:

npm install gulp

to update gulp, which now produces this error:

tim: ~/Sites/mysite $ gulp
    throw err;

Error: Cannot find module 'laravel-elixir'
    at Function.Module._resolveFilename (module.js:538:15)
    at Function.Module._load (module.js:468:25)
    at Module.require (module.js:587:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/tim/Sites/mysite/gulpfile.js:1:78)
    at Module._compile (module.js:643:30)
    at Object.Module._extensions..js (module.js:654:10)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)

So I ran

npm install laravel-elixir-webpack-official --save-dev

Which didn't do a thing; still receiving the Error: Cannot find module 'laravel-elixir' error.

I've tried moving from Gulp to Mix and have received a tremendous amount of errors as well, which made me go back to Gulp. I've spent hours on this over the course of two weeks and can not find a solution.

I really don't know what to do at this point, but my app is broken until I get this fixed.

timgavin started a new conversation Elixir To Mix

Elixir is no longer working for me so I'm planning on moving over to Mix. I want to make sure I understand and am doing this correctly before moving all my stuff over.

Is it as simple as changing this...

elixir(function(mix) {
    ], 'public/js/app.js');

to this?

], 'public/js/app.js');

Basically just removing the elixir(function(mix) {?

28 Dec
1 year ago

timgavin left a reply on Mail CC Sends Twice

@Snapey That was it!

I'm using Forge and have 2 load balanced servers. I was running artisan schedule:run on each one every minute. D'oh!


timgavin left a reply on Mail CC Sends Twice

In the mailable, the recipients are only be looped through to show their username. I don't think I'm calling it twice?

Here's the code...


class Kernel extends ConsoleKernel
    protected $commands = [

    protected function schedule(Schedule $schedule)

    protected function commands()
        require base_path('routes/console.php');


class ReportNewSignups extends Command
    protected $signature = 'report:signups';

    protected $description = 'Daily total of new users';

    public function handle()
        $today = Carbon::today();

        $users = User::whereDate('created_at', $today)->get();

        Mail::to('[email protected]')
            ->cc('[email protected]')
            ->send(new \App\Mail\Reports\NewSignups($users, $today));


class NewSignups extends Mailable
    use Queueable, SerializesModels;

    public $users;
    public $today;

    public function __construct($users, $today)
        $this->users = $users;
        $this->today = $today;

    public function build()
        return $this->view('emails.reports.signups');



    <p style="{{ $style['p'] }}">
        {{ $users->count() }} @if($users->count() == 1) signup @else signups @endif for {{ $today->toFormattedDateString() }}
    <p style="{{ $style['p'] }}">
        @foreach($users as $user)
            <a href="{{ linkToUser($user->username) }}">
                <?php echo '@'.$user->username ?>


timgavin started a new conversation Mail CC Sends Twice

Why would this send two emails to each email address?

Every time I use CC it sends 4 emails instead of two; in multiple apps as well. Am I missing a config setting or something?

Mail::to('[email protected]')
    ->cc('[email protected]')
    ->send(new NewSignups($users));
22 Dec
1 year ago

timgavin left a reply on Require.extensions.hasOwnProperty Is Not A Function

@bkno I added this but it didn't fix it for me. Am I supposed to do something after adding it? Ran: composer dump autoload but that didn't make a difference.

16 Dec
1 year ago

timgavin left a reply on Relationship Not Returning A Collection

that was it. thanks! :)

timgavin started a new conversation Relationship Not Returning A Collection

A User can refer another User to the website.

In my users table, I have a referred_by column which holds the user Id of the referring user.

When listing users, I want to show who referred whom, so I set up a relationship in my Users model

// a user has one referrer
public function referrer()
    return $this->hasOne(User::class, 'referred_by');

However, this returns null, so I changed it to this

// a user has one referrer public function referrer() { return $this->belongsTo(User::class, 'referred_by'); }

Which returns a result, but it's not a collection, so I can't do {{ $user->referrer->username }} to display the referrer's username. And when I do `dd($user->referrer)` it returns `null`, even though there's data returned.

How do i solve this?

timgavin started a new conversation Question Regarding First()

I was putting auth()->user() into a variable and made the mistake of putting first() at the end...

$user = auth()->user()->load('profile')->first();

Of course, this confused the hell out of me because I kept seeing the wrong user information and couldn't understand why, until I removed first() and everything worked.

So now I'm a little confused.

Why would auth()->user()->load('profile')->first() show the first user in the database (even though I'm using the authenticated user), but User::where('id', 244)->first() gets the first row matching the query params, which is user 244?

03 Dec
1 year ago

timgavin started a new conversation Invalid Token Errors When Trying To Tweet

I'm using the ThuJohn Twitter package and am trying to post tweets as a site user, but keep getting [89] Invalid or expired token errors.

I know the package is installed correctly because I can send tweets using the website's app credentials; it's when I'm trying to tweet as a site user I run into problems.

I'm using the reconfig method, yet am still encountering issues. I'm wondering if my user credentials are wrong?

Here's the reconfig method:

    'consumer_key' => env('TWITTER_CONSUMER_KEY'),
    'consumer_secret' => env('TWITTER_CONSUMER_SECRET'),
    'token' => $user->twitter->token,
    'secret' => $user->twitter->secret

And this is how I'm grabbing the user's token and secret inside the callback method. Is this the correct way?

$request_token = [
    'token'  => Session::get('oauth_request_token'),
    'secret' => Session::get('oauth_request_token_secret'),
04 Nov
1 year ago

timgavin started a new conversation SSH Confusion

I know this is really simple but I always get confused by the order of the process, so I'd like a record of it - and incase anyone else comes across this it may help them too.

I have a Forge server set up as a Redis cache/session/queue server.

I need to access the Redis server from my Laravel app which is on another Forge server.

What are the steps and commands for generating an SSH key on the Laravel server and installing it on the Redis server, so that I may access the Redis server via my Laravel app?

Thank you!

timgavin left a reply on Post Won't Delete Using Job

@robrogers3 I Think I got it sorted out this morning. It appears to have been a misconfiguration with my redis server. After a couple of hours tearing things down and putting them back together it appears to be working.

I've created a new post asking for a review of my settings to see if I've now got things set correctly: https://laracasts.com/discuss/channels/laravel/please-look-over-my-redis-configs

Thanks for your help! :)

timgavin started a new conversation Please Look Over My Redis Configs

I've set up a separate server for redis queues, caching and sessions. So far it seems to be working okay, but I'd like to verify that I've set everything up correctly. The documentation is kinda sparse regarding this so I've just been patching together different posts and articles from around the web and hoping it's right.

I'm using Forge and am deploying via Envoyer. My 2 load balanced servers and the redis server all receive code deployments.

I've set up a site on my redis server and have queue instances; one named redis, which is for the default queue, and one named redis_posts for the posts queue, as well as a Horizon daemon.

In order to restart Horizon after a deployment, I have set up an Envoyer deployment hook to terminate horizon workers, which runs after the Activate New Release hook.

cd {{ release }}
php artisan horizon:terminate

I'm assuming (because I'm not sure how to change this) that the redis sessions will use database 0, as I've set the redis queues to use databases 1 and 2.

Following are my Laravel config files





'redis' => [

    'client' => 'predis',

    'default' => [
        'host' => env('REDIS_HOST', ''),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,



'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => 'default',
    'retry_after' => 90,
    'database' => 1,
'redis_posts' => [
    'driver' => 'redis',
    'connection' => 'redis_posts',
    'queue' => 'posts',
    'retry_after' => 90,
    'database' => 2,


'redis' => [
    'driver' => 'redis',
    'connection' => 'default',


'connection' => null,