sustained

sustained

Member Since 10 Months Ago

Sheffield

Experience Points 31,710
Experience Level 7

3,290 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed 274
Lessons
Completed
Best Reply Awards 5
Best Reply
Awards
  • start-engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-session Created with Sketch.

    School In Session

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

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

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

  • subscriber-token Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer-token Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • lara-evanghelist Created with Sketch.

    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 Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

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

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

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

24 Jul
1 month ago
21 Jul
1 month ago

sustained left a reply on Passport Token Is Still Valid After Revocation (even Deletion)?

Hey, thanks for replying.

No, the test fails in precisely the same way if I try to delete the token(s) that way instead.

sustained started a new conversation Passport Token Is Still Valid After Revocation (even Deletion)?

I have a test that:

  • creates a user
  • hits the login endpoint to get a token
  • hits the logout endpoint to revoke a token (tried deleting too)
  • hits the user endpoint to make sure the token was revoked (this part fails)

I don't understand what the problem is. I'm getting a 200 and the user data is being returned even after revoking (and/or deleting) the token.

This is the relevant part of the AuthController:

    public function logout(Request $request)
    {
        try {
            $request->user()->token()->revoke();
            $request->user()->token()->delete();

            return response()->json([
                'type' => 'logout_success',
                'message' => 'User logged out.'
            ]);
        } catch (Exception $e) {
            return $this->respondWithGenericError($e);
        }
    }

And the relevant part of the test:

<?php
class AuthTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp() : void
    {
        parent::setUp();

        \Artisan::call('migrate');
        \Artisan::call('passport:install');
    }

    public function test_that_tokens_are_revoked_upon_logout()
    {
        $user = factory(\App\User::class)->create();

        $response = $this
            ->postJson('/api/auth/login', [
                'email' => $user->email,
                'password' => 'password' // NOTE: Is default password set by User factory.
            ])
            ->assertJsonStructure([
                'access_token',
                'expires_at',
                'token_type'
            ]);

        $this
            ->actingAs($user)
            ->getJson('/api/auth/logout', [
                'Authorization' => 'Bearer ' . $response->json()['access_token']
            ])
            ->assertJsonFragment(['type' => 'logout_success']);

        // FIXME: Why do we get a 200?
        $this
            ->actingAs($user)
            ->getJson('/api/auth/user', [
                'Authorization' => 'Bearer ' . $response->json()['access_token']
            ])
            ->assertStatus(401);

        // $this
        //     ->assertDatabaseHas('oauth_access_tokens', [
        //         'user_id' => $user->id,
        //         'revoked' => true
        //     ]);
    }
}
16 Jun
3 months ago

sustained left a reply on Auth Choices For SPA + Internal/closed API.

I mean, the "main" JWT library for Laravel has 398 open issues and 13 open pull requests. It just doesn't exactly inspire confidence in the hip and cool new JWT movement. Auth is important and should be done right.

It's the reason I went with default Laravel auth scaffolding until now - I trust them.

sustained started a new conversation Auth Choices For SPA + Internal/closed API.

It seems like there's a million different ways to implement auth and it can be a bit overwhelming.

There's Passport, there's JWTs, there's the token driver, there's just using the web routes with an api prefix and probably more options.

In the case that you have a Laravel app and that Laravel app serves a Vue SPA which wants to consume its own (the Laravel) API, which option should one use?

At this point in time, my API will be closed/internal/only for self-consumption.

Are JWTs the "correct" answer? But in the future I'll likely open up my API, so I want to be future-proof. Also I don't want to lock myself out of the possibility of having some good old-fashioned Laravel backed routes that still work with auth.

Up until now, I've had all my API routes in web.php in a group with an api prefix and an ajax middleware and have been using the default Axios setup (that sends CSRF tokens etc.) but now I'm at the stage where I'd like to move the login/register etc. stuff that comes with the Laravel auth scaffolding into the SPA itself.

But it seems like that default auth scaffolding just isn't designed to accommodate that use-case, correct? So now I will be forced to get my hands dirty and write some auth code, as opposed to using what Laravel provides?

I just really don't want to get auth wrong and I don't particularly trust these thousands of tutorials and guides that all do things in slightly different ways. I have no doubt many of them are flawed, security-wise and I've read about various security concerns with JWTs.

I wish that the Laravel docs had some comprehensive information on doing auth properly with a Vue SPA that self-consumes its own Laravel API, or that there was a course which covered this in detail. There is this series but so far it's only covering the use-case of an app on one domain consuming the API of a separate Laravel app on another domain which is not at all what I want.

Thanks for reading!

08 Jun
3 months ago

sustained started a new conversation And Tips/advice On Testing Scheduled Tasks?

This is essentially a cross-post for this request.

Has anyone ever successfully applied TDD to the task scheduler? If so, I'd appreciate any information at all you can share on the process.

As I mentioned in the other thread, I don't see how one could possibly mock something like the scheduler cron job.

And you'd need to fake advances of system time within said process, but from the tests.

Is this even possible?

sustained started a new conversation Request For Lesson(s) On Testing Scheduled Tasks + Jobs/queues.

This requests subforum is for requesting videos on specific topics, right?

I'm working on an application that will rely heavily on jobs/queues and scheduled tasks. Them working properly, flawlessly even, will be vital and as such I think I need to apply TDD here.

There is some information available on testing jobs/queues but I can't even imagine how one begins to test scheduled tasks.

You'd have to somehow have the scheduler running in the context of the tests (I don't see how such a thing could be mocked) and you'd need to fake advances of system time and have the actual scheduler react to them.

I can't even begin to imagine how this would be accomplished.

Perhaps this would make for a good advanced lesson.

25 Dec
8 months ago

sustained left a reply on In Vue.js, Does It Make A Difference If I Call A Function With Parentheses?

Because with axios.get you want to give it a string and getUrl returns a string so you call the function whereas with .then it wants a callback and so you need to pass it a function, if you passed it the result of calling refresh then it would evaluate to undefined which isn't a callback.

sustained left a reply on Customizing The Message In Laravel's New Error Pages?

@THEBIGK - I was getting the same error at one point when my view was NOT in /resources/views/errors/ but when I moved it into that exact directory that error went away.

I never did find out what exactly was going on.

Laravel version? 5.7 or lower?

You can always as a temporary stopgap copy the layout file into the errors directory and use errors.layout instead, see here.

22 Dec
8 months ago

sustained left a reply on Forge Support?

@_STEFANZWEIFEL - Aye, as I figured out myself eventually it was my ad blocker!

17 Dec
9 months ago

sustained left a reply on Forge Support?

I also can't find any form of support widget or link to a support section or anything anywhere on their site. Seriously thinking of cancelling my subscription because of it.

Resurrecting this dead thread because it was the first result for "Laravel Forge support" on Google - go figure.

sustained left a reply on Flash Session After Sending Verification Email

Can you add some kind of logging to the registered method to make sure it's getting called? Perhaps a dd or something?

sustained left a reply on Auth In Browser / Vue App

No problem! I too am taking the API routes in web.php route for now and plan to look into Passport etc. later on. Apparently a lot of people do this, from what I've read and heard.

It's important to understand that the api.php file is for STATELESS APIs only... but cookies and sessions are, of course, stateful data.

sustained left a reply on Customizing The Message In Laravel's New Error Pages?

The abort helper raises an exception which will then be caught by the exception handler, which will decide which view to render. As such, aborting and the rendering of error pages is tied to the HTTP status code.

You can see what the views look like by navigating to the vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views/ directory, they are rather simple.

You are free to override them on a status code-by-status code basis by creating a file in your resources/views/errors directory as you have found out.

You are also free to extend the built-in layout when you do so, if that's how you want them to look:

@extends('errors::illustrated-layout')

Some of the error pages, like the 403 page, do actually allow you to display a message by default because of this line of code in the view:

@section(
    'message',
    __($exception->getMessage() ?: 'Sorry, you are forbidden from accessing this page.')
)

As you can see, if there is a message it will be displayed.

Try it yourself with abort(403, 'my message');.

Others like the 404 page instead have something like this:

@section('message', __('Sorry, the page you are looking for could not be found.'))

You are free to change any template to use $exception->getMessage(), just like the 403 error page does, then the message passed to abort will be displayed.

16 Dec
9 months ago

sustained left a reply on Auth In Browser / Vue App

The easiest option is to put your API routes in web.php, thereby giving you access to cookies and session state and such.

Another option is probably to use Passport and access tokens and such, see here.

13 Dec
9 months ago

sustained left a reply on How Inportant Is Xcode For Us As PHP And Javascript Developers?

I personally just use VS Code for all development on all OSes.

You'll only need XCode if you ever need to compile to native code.

It's certainly feasible that a web dev might have a need to do so nowadays, due to the existence of things like React Native; Electron and so on.

sustained left a reply on Manage Multiple Servers

You can host multiple sites/instances of Laravel on a single Forge server/DigitalOcean droplet.

I am using Forge (hobby) + DO and I have three separate Laravel sites on a single droplet, with no problems.

Then at a future time if and when a single server can no longer manage your traffic, you can upgrade.

11 Dec
9 months ago

sustained left a reply on Can't Get Run Laravel Telescope

What is the actual error in the log file, or printed to the console (if using php artisan serve)...

sustained left a reply on Learn It All Wrong First?

People learn to stumble and fall constantly before they learn to walk.

People learn to throw broken sentences together before they learn to speak a language.

It's a perfectly valid and natural method of learning, for kids and adults too.

So my question is - why not?

sustained left a reply on Is There One Artisan Command That Clears All Caches?

One solution is to add an entry to your package.json?

{
    ...
    "scripts": {
        ....
        "clear-cache": "php artisan cache::clear && php artisan config::clear && php artisan route::clear && php artisan view:clear"
    }
}

Then run npm run clear-cache?

10 Dec
9 months ago

sustained left a reply on Register Dynamic Model Events From Static Trait Boot Method.

Apparently I'm far too used to JavaScript closures.

It works fine if I add a use statement:

    protected static function bootRecordsActivity()
    {
        foreach (static::$activities as $eventName) {
            static::$eventName(function ($model) use($eventName) {
                $model->record($eventName);
            });
        }
    }

sustained left a reply on Javascript Push Removing Previous Item From Array

Please create a minimal "working" example with some actual example data using a tool like JSFiddle or CodePen.

This will help people to help you.

sustained started a new conversation Register Dynamic Model Events From Static Trait Boot Method.

In episode 25 of Let's Build a Forum with TDD we start working on adding an activity feed.

After we get our tests passing, we extract the code to a trait which we can use in all of our models.

The trait looks something like this:

<?php

namespace App;

trait RecordsActivity
{
    protected static function bootRecordsActivity()
    {
        static::created(function ($model) {
            $model->record('created');
        });
    }

    public function activities()
    {
        return $this->morphMany(Activity::class, 'subject');
    }

    public function record($eventName)
    {
        $this->activities()->create([
            'action' => $eventName,
            'user_id' => auth()->id(),
            'subject_id' => $this->id,
            'subject_type' => get_class($this)
        ]);
    }
}

Now I figured I could take this slightly further so first I added this to my Thread model:

    protected static $activities = [
        'created'
    ];

Next I modify bootRecordsActivity:

    protected static function bootRecordsActivity()
    {
        foreach (static::$activities as $eventName) {
            static::$eventName(function ($model) {
                $model->record($eventName);
            });
        }
    }

But this doesn't work as expected.

It's looking for a static::$eventName property in the Thread model but I instead want to call a static method (static::created) dynamically. I then tried static::{$eventName} but no dice.

Is there a clean way to achieve this? I'm pretty new to PHP (well, it's been many years).

I tried googling and attempted some stuff with get_called_class and such but didn't have any luck.

Thanks!

08 Dec
9 months ago

sustained left a reply on Register/Login An API Session To My Site From Within Another Website

As far as I understand, the generally accepted way to allow other websites to do anything along these lines is by making use of OAuth2.

Have you taken a look at Passport?

sustained left a reply on Not Able To Deploy

Odd. Personally I'd first try just destroying and recreating the app and/or server.

sustained left a reply on ES6 Class Does Not Work In Compiled Js

Perhaps this...

if (typeof window === 'undefined')
    export default Point;
else
    window.Point = Point;

No idea what best practice is though regarding this.

Since the stuff I import/require in my app/main JS file are only being used in the browser personally I just do stuff like window.Blah = require('blah'); or import Blah from 'blah'; window.blah = Blah;.

sustained left a reply on Automatic DB Seeding For Tests.

Nah, I never seed the DB in migrations.

I'll take a look at the packages and versions between both versions.

07 Dec
9 months ago

sustained left a reply on No Queries Being Exected With Route-model Binding?!

I generally always do. I just don't sit on the Laracasts forum all day.

sustained left a reply on No Queries Being Exected With Route-model Binding?!

Huh, I feel like I've already learned this... my memory seems to be leaking. :/

sustained started a new conversation Automatic DB Seeding For Tests.

On one of my projects I don't need to call $this->seed() or $this->artisan('db:seed') at all and seeding just works by default.

On another project I just started, I have to call those in setUp otherwise the DB is blank.

Both are using SQlite and :inmemory:, same version of PHP+Laravel+SQlite, same machine even.

Both are using the same base TestCase:

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
    use RefreshDatabase;
    // use DatabaseMigrations;
}

I don't understand.

sustained started a new conversation No Queries Being Exected With Route-model Binding?!

Why is implicit route-model binding not working for me? I have this route in api.php:

Route::get('guild/{discord_id}', '[email protected]');

And this model:

class Guild extends Model
{
    public function getRouteKeyName()
    {
        return 'discord_id';
    }
}

And this controller:

class GuildController extends Controller
{
    public function show(Request $request, Guild $guild)
    {
        return $guild;
    }
}

I have removed use statements etc. for clarity.

If I setup the binding explicitly in RouteServiceProvider.php then it works?

    public function boot()
    {
        parent::boot();

        Route::bind('guild', function ($value) {
            return Guild::where('discord_id', '=', $value)->first();
        });
    }

If I check Telescope, no queries are even being executed?

06 Dec
9 months ago

sustained left a reply on Ajax POST MethodNotAllowedHttpException

It happens to us all.

sustained left a reply on Disable Updated_at Time Of Insert

@SOUVIKBHATTACHARYAS - I too will be waiting to see what other suggestions show up, out of curiosity.

Just mark me as the best answer, if you decide to go with my solution/nothing better comes along though? :D

sustained started a new conversation Very Strange Behaviour When Using ::class In Routes File.

This doesn't make any sense?

use App\Http\Controllers\ReplyController;

Route::resource('threads', ThreadController::class);
Route::post('/threads/{thread}/replies', [ReplyController::class, 'store']);

// ^ All routes work.
Route::resource('threads', ThreadController::class);
Route::post('/threads/{thread}/replies', [ReplyController::class, 'store']);

// ^ Only the routes on the threads resource work, otherwise:
// ReflectionException, Function () does not exist
use App\Http\Controllers\ThreadController;
use App\Http\Controllers\ReplyController;

Route::resource('threads', ThreadController::class);
Route::post('/threads/{thread}/replies', [ReplyController::class, 'store']);

// ^ Only the store reply route works, otherwise:
// App\Http\Controllers\App\Http\Controllers\ThreadController does not exist
use App\Http\Controllers\ThreadController;

Route::resource('threads', ThreadController::class);
Route::post('/threads/{thread}/replies', [ReplyController::class, 'store']);

// ^ None of the routes work:
// App\Http\Controllers\App\Http\Controllers\ThreadController does not exist

I would expect either #2 or #3 to be the one where all routes work???

sustained left a reply on Disable Updated_at Time Of Insert

I don't see what's wrong with it either but...

Extend the model class and use eloquent events e.g.

<?php
use Illuminate\Database\Eloquent\Model;

class CustomModel extends Model
{
    public static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            $model->timestamps = false;
            $model->created_at = now();
        });
    }
}

Code is untested.

Disclaimer: I'm a Laravel newb so this might not work or might be really bad code etc.

sustained left a reply on How Can I Add A New Repo From An Existing Project And Connect It To Github Or Gitlab

Just create a new completely empty repository on Gitlab and then scroll down and read the "command line instructions" section.

sustained left a reply on Ajax POST MethodNotAllowedHttpException

Change Route::get to Route::post.

sustained left a reply on Testing Environment Is Not Set When Running Phpunit?

CONFIG CACHING STRIKES AGAIN, ANOTHER VICTIM CLAIMED!

sustained started a new conversation Testing Environment Is Not Set When Running Phpunit?

At around 8:25 in episode 4 of Let's Build a Forum with TDD, Jeff mentions a gotcha with Laravel testing in that sending e.g. a POST request to a nonexistent endpoint doesn't trigger an error like you'd expect.

He mentions a walkaround wherein one can edit the render method within app/Exceptions/Handler.php and throw the exception if the app environment is testing i.e.:

public function render($request, Exception $exception)
{
    if (app()->environment() === 'testing') throw $exception;
}

But if I try to apply the workaround, it doesn't work as expected.

If I do a \Log::debug(app()->environment()) within that method, I can see that it returns local when I run vendor/bin/phpunit.

Is this a bug? Is there a new/different workaround for this issue for Laravel 5.7?

05 Dec
9 months ago

sustained left a reply on Laravel And Gzip... How To?

But that is for compressing some specific file, like a report that you've generated in that case.

If you want to compress all of your public assets then it's best to do it at the webserver level?

sustained left a reply on Laravel And Gzip... How To?

I believe gzip is something that happens at the webserver level, so you need to google for how to enable gzip with Apache or Nginx or whatever webserver you're using.

You can probably even include your OS in the search and you should be able to find detailed instructions on how to set it up.

Example search term: linux ubuntu 16.04 nginx server setup gzip compression and the first Google result for that search.

Using Ubuntu 16 as an example because it's exceedingly popular.

sustained left a reply on Proper Queue Usage?

Another approach could be to batch them so that the first job is responsible for sending say 20 Slack messages and the second job for the next 20 and so on.

This way, if one of the jobs fails only a small number of messages fail to send and the number of people affected is minimal.

sustained left a reply on Flash Session After Sending Verification Email

I believe you can add a method called registered to your Auth\RegisterController.

In the file vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers there is a method called register which validates the request, fires a Registered event, logs in the user and then the last part looks like this:

        return $this->registered($request, $user)
                        ?: redirect($this->redirectPath());

So what it does is it checks if the return value of calling registered is truthy then it returns that, otherwise if it is non-truthy (which is the default because by default registered does nothing) then it redirects based on the redirectPath.

And the definition of redirectPath looks like this:

    public function redirectPath()
    {
        if (method_exists($this, 'redirectTo')) {
            return $this->redirectTo();
        }

        return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
    }

So you can probably create the registered method as I said and make it look something like this:

<?php
class RegisterController extends Controller
{
    use RegistersUsers;

    protected $redirectTo = '/home';

    protected function registered(Request $request, $user)
    {
        $request->session()->flash('foo', 'bar');
        // Any other logic needed.
    }
}

And if you want it to redirect after then make sure that you return false/null/nothing and define redirectTo as either a method or a property.

Sorry if this is not super clear or if I'm incorrect or if there are easier/better ways to achieve this or whatever, I'm brand new to Laravel.

EDIT: Typos fixed.

sustained left a reply on Consuming Jobs From Laravel Queues With Node

I just ended up creating a NodeJob model and basically creating my own custom implementation.

sustained left a reply on Laravel Custom Url Set

It's very easy to conditionally redirect the user with any framework, including Laravel.

sustained left a reply on Laravel Websockets

I saw this on the Laravel subreddit the other day, looks interesting!

sustained left a reply on Dynamic Routes

Originally I was trying to do this, which I thought would work just fine but it doesn't (hence the above solution):

Route::get('/dynamic/{params?}', function ($method, $params = null) {
    return App::call('\App\Http\Controllers\[email protected]', explode('/', $params));
})->where('params', '.+');

And this controller:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class DynamicController extends Controller
{
    public function handle(Request $request, $one = null, $two = null, $three = null)
    {
        dd([$one, $two, $three);
    }
}

Those params are ALWAYS null for me instead of just defaulting to null which I don't understand.

Does anyone know why?

If you change it to e.g. handle(Request $request, $one, $two) and pass exactly two params it works just fine?

sustained left a reply on Dynamic Routes

You could have this route:

Route::get('/dynamic/{params?}', function ($method, $params = null) {
    return App::call('\App\Http\Controllers\[email protected]');
})->where('params', '.+');

And this controller:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class DynamicController extends Controller
{
    public function handle(Request $request)
    {
        $params = array_slice($request->segments(), 1);
        dd($params);
    }
}

EDIT: FIxed typo.

sustained left a reply on Filter Json Object By Keys

Does this help?

https://jsfiddle.net/sustained/L586gvh9/

If not then I have misunderstood the format of your data before transformation as well as the format you want it to be transformed into and you need to be more specific.