sustained

sustained

Member Since 4 Months Ago

Sheffield

Please hire me at once!

Experience Points 19,980
Experience Level 4

20 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 159
Lessons
Completed
Best Reply Awards 5
Best Reply
Awards
  • 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

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • Lifer Achievement

    Lifer

    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.

25 Dec
2 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
2 months ago

sustained left a reply on Forge Support?

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

17 Dec
3 months ago

sustained left a reply on Forge Support?

@MDECOOMAN - I 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.

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

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 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 copy the built-in layout, and just display your own message.

Some of the error pages, like the 403 page, do actually allow you to display the message 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 override the entire template for any HTTP error, as I mentioned before above, and use $exception->getMessage() just like the 403 error page does.

16 Dec
3 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 stat and such. Another option is probably to use Passport and access tokens and such, see here.

13 Dec
3 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.

sustained left a reply on Manage Multiple Servers

You can host multiple servers on one DigitalOcean droplet. I have three on my Forge server.

You can then upgrade at a future time if and when the single server can no longer manage your traffic.

11 Dec
3 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?

Kids learn to stumble and fall constantly before you learn to walk. Kids learn to throw broken sentences together before you learn to speak a language.

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

So my question is - why not?

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

You could add an entry to your package.json?

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

Then run npm run clear-cache?

10 Dec
3 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 ($thread) {
                $thread->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.

Is there a clean way to achieve this? I tried googling and attempted some stuff with get_called_class and such but didn't have any luck.

Thanks!

08 Dec
3 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
3 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?!

@CRONIX - 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?

06 Dec
3 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

sustained left a reply on Disable Updated_at Time Of Insert

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, Jeff mentions a gotcha with Laravel testing in that sending a request that doesn't have a route/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
3 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.

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.

This method will be fired immediately after logging in the user (after registration) and immediately before redirecting the user.

The code in question that calls this method is in vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers and looks like this:

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

So if the return value of registers is truthy then it returns that, otherwise if it is non-truthy (which is the default because by default it 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.

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.

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);
    }
}

04 Dec
3 months ago

sustained started a new conversation Consuming Jobs From Laravel Queues With Node

Does anyone have any experience with this or any ideas/input? Or perhaps an alternative method of communicating with my node program from Laravel?

My current setup is thus:

  1. I have one server running a long-running Node process (let's call it node) as well as a Laravel app that acts as a purely private API (let's call it papi. The server as a whole, let's call node/papi.
  2. I also have a second server which is also a Laravel app but this one is publicly accessible (via the web), let's call this server web.

Note that web is also able to communicate with papi.

So, the web server is going to be powering a relatively complex web application and so I will be using jobs/queues for various things, most likely. And most of these I'll want to consume from PHP/Laravel code.

But now and again, I'll need a job triggered from web to be ultimately processed by node.

I'm thinking that I can just have a second job queue setup on papi which is solely for node-specific jobs.

Then I can presumably just not run any queue worker at all on the node/papi server and instead consume those jobs from Node/JS.

But this all feels a little clunky. Any input appreciated.

03 Dec
3 months ago

sustained left a reply on Redirect

Question: If you're using Laravel then why not do it server-side?

You could check document.referrer to see where the user came from and you can use window.location = 'url to redirect to'; to redirect the user?

If you still can't get it working, post example code?

sustained left a reply on How To Install Vuex

Try this:

  1. Install Vue CLI 3 - npm i @vue/cli -g.
  2. Create a new project - vue create myproject (you may need to close and reopen the terminal window first, after step 1).
  3. When prompted to select a preset, choose "manually select features".
  4. Use arrow key down, until you hit Vuex, then hit space.
  5. Select whatever you want for linter, lint features, config location etc. (the default is fine - just hit return).
  6. You should have a working Vue project with VueX boilerplate and Babel compilation etc.

sustained left a reply on Moving To Laravel Platform

I second @d9705996's suggestion to watch this series, it gave me a great feel for the framework very quickly.

sustained left a reply on Disable A Selectbox

And with Vue:

<div id="app">
    <select id="type" name="type" v-model="selected">
        <option value="free">Free</option>
        <option value="vip">VIP</option>
        <option value="cash">Cash</option>
    </select>

    <input type="text" id="price" name="price" :disabled="userCanEnterPrice">
</div>

<script>
new Vue({
    el: 'div#app',
    
    data: {
        selected: null
    },
    
    computed: {
        userCanEnterPrice() {
            return ['free', 'vip'].includes(this.selected);
        }
    }
});
</script>

sustained left a reply on Modifying Form Data From Request

Just like @Talinon, I personally don't really see the issue with the options presented in the original post.

One could definitely argue that this does count as validation, and I in fact would. But what's the use in arguing about whether or not this should be classified as validation? Does it really matter?

It's kind of hard to avoid the fact that a modern application consists of many many layers. I don't think that any of the ideas presented in the original post are particularly bad.

Just pick one and roll with it and if it becomes a problem in the future then refactor.

Personally out of those three options, my first choice would be validation and my second would be a "normalisation layer" anyway.

sustained left a reply on Modifying Form Data From Request

Hmm, fair enough. It seemed like a simple/elegant enough solution to me, in this case. I can see how excessive use could become unwieldy though.

I mean, realistically you have 3 options:

  1. Your backend code deals with it. Be that the model layer or in some data normalising layer or at the middleware layer or whatever else.
  2. You handle this on the client-side (so the server never even receives feet and inches - it gets converted to metric before ever being sent).
  3. You handle it at the database layer (pretty sure some databases are capable of such things).

Personally I'm leaning towards #2, especially if you're using something like Vue.

Just some more food for thought.