johncarter

johncarter

Member Since 2 Years Ago

Hertfordshire / London

Experience Points
9,360
Total
Experience

640 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
87
Lessons
Completed
Best Reply Awards
0
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.

Level 2
9,360 XP
Nov
20
2 months ago
Activity icon

Replied to Installing Larval Best Practice

Can I suggest using Laragon for Windows? I wouldn't say it's best practice but it's easy to get going.

Install it and use Quick App > Laravel. It does all the db creation, http conf, SSL, Laravel install in one hit.

https://laragon.org/

Nov
01
2 months ago
Activity icon

Started a new Conversation Derived Status Attribute

I have a number of queries that determine if a model has a specific "status":


    public function scopeExpired($query)
    {
        return $query->doesntHave('bids')->whereRaw('deadline < TIMESTAMPDIFF(MINUTE,created_at,NOW())');
    }
   
    public function scopeOpen($query)
    {
        if (auth()->user()->isSupplier()) {
            return $query->whereDoesntHave('bids', function ($subquery) {
                $subquery->whereNotNull('accepted_at');
            })->whereDoesntHave('bids', function ($subquery2) {
                $subquery2->where('user_id', auth()->user()->id);
            })->notExpired();
        } else {
            return $query->doesntHave('bids')->notExpired();
        }
    }
   // ... plus 5/6 more local scopes that determine statuses

I need to be able to access the status that scopes define as a dynamic property like this:

{{ $model->status }} // expecting expired / open / etc

How do I best approach this?

Oct
23
3 months ago
Activity icon

Awarded Best Reply on SignedRoute In Test Causes BadMethodCallException

Turns out this was an issue with my local development environment.

I ended up having to delete

C:\Users\USERNAME\AppData\Roaming\Composer\vendor
C:\Users\USERNAME\AppData\Roaming\Composer\composer.lock

Then run:

composer global install

Hope that might help someone else out.

Activity icon

Replied to SignedRoute In Test Causes BadMethodCallException

Turns out this was an issue with my local development environment.

I ended up having to delete

C:\Users\USERNAME\AppData\Roaming\Composer\vendor
C:\Users\USERNAME\AppData\Roaming\Composer\composer.lock

Then run:

composer global install

Hope that might help someone else out.

Activity icon

Started a new Conversation SignedRoute In Test Causes BadMethodCallException

Rightly or wrongly, I'm using a signedRoute in my users.update route to protect users modifying the user id of the edit user form. Please tell me if that is bad news and tell me another way around it if possible.

Anyway, as a result when I write a test I get a BadMethodCallException: Method Illuminate\Support\Arr::query does not exist. error and I don't why. Can someone help me:

Test

use Illuminate\Support\Facades\URL;

class UserTest extends TestCase
{
    function adminCanChangeUserStatus()
    {
            $this->withoutExceptionHandling();

        // hard coded user and fail() method for debug
            $this->fail(URL::signedRoute('users.update', ['user' => 9]));
    }
}

Routes

Route::group(['middleware' => ['auth']], function () {
    ....
    Route::post('users/{user}', '[email protected]')->name('users.update');
    ....
});

UserController

public function update(User $user)
{
        abort_if(!request()->hasValidSignature(), 401);
    ...

}

When I run the test above it throws the following stack trace:

BadMethodCallException: Method Illuminate\Support\Arr::query does not exist.

C:\Users\USERNAME\AppData\Roaming\Composer\vendor\illuminate\support\Traits\Macroable.php:75
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Routing\RouteUrlGenerator.php:268
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Routing\RouteUrlGenerator.php:247
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Routing\RouteUrlGenerator.php:88
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Routing\UrlGenerator.php:428
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Routing\UrlGenerator.php:409
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Routing\UrlGenerator.php:333
C:\laragon\www\sitename\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php:239
C:\laragon\www\sitename\tests\Feature\UserTest.php:92
C:\Users\USERNAME\AppData\Roaming\Composer\vendor\phpunit\phpunit\src\TextUI\Command.php:200
C:\Users\USERNAME\AppData\Roaming\Composer\vendor\phpunit\phpunit\src\TextUI\Command.php:159
Oct
15
3 months ago
Activity icon

Replied to Reply-To On Queued Mail Instance

That's fixed it, thanks again @nakov - I really appreciate your time.

Activity icon

Started a new Conversation Reply-To On Queued Mail Instance

How do I set the Reply-To header on a queued Mail instance:

Mail::to('[email protected]')
            ->queue(new \App\Mail\ContactFormSubmission($validatedData));
public function build()
{
    return $this->replyTo('[email protected]', 'Dave')->markdown('emails.contact_form.submission');
}

If I use the ->send() method it's fine, but if I use ->queue the header is not set.

Thanks in advance.

Oct
14
3 months ago
Activity icon

Replied to Conditional Validation On Arrays

More easy to scan to the solution, but as you asked I'll change it to yours. Sorry.

Activity icon

Replied to Conditional Validation On Arrays

That's got it! nullable - so simple

'bid_lines.*.brand' => ['required_without:bid_lines.*.main_dealer', 'nullable', 'in:genuine,oe,aftermarket'],

Thanks very much @nakov!

Activity icon

Replied to Conditional Validation On Arrays

What about not even POSTing the data in the first place? So when that checkbox is selected I remove it from the DOM then use sometimes? Any reason that's bad?

Activity icon

Started a new Conversation Conditional Validation On Arrays

I have a Form Request that has some validation rules conditionally met on a checkbox (main_dealer) being checked:


    public function rules()
    {
        return [
            'bid_lines.*.description' => ['required', 'min:3', 'max:100', 'string'],
            'bid_lines.*.brand' => ['required_without:bid_lines.*.main_dealer', 'in:genuine,oe,aftermarket'],
        ];
    }

The above required_without code works - the brand select input isn't required if the main_dealer checkbox is checked.

The problem is that the in: condition is still being triggered even if it's not required, so is failing. Can someone help me figure this out?

Sep
11
4 months ago
Activity icon

Replied to Change Validation Message :attribute Placeholder For Array Inputs

Thanks for everyone's help. I managed to get it working by:

php artisan make:request StoreLines

Then adding the following method:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreLines extends FormRequest
{

    public function rules()
    {
        return [
            // Your rules... e.g. 'line.*.description' => ['required', 'max:255'],
        ]
    }

    public function messages()
    {
        $messages = [];
        foreach ($this->request->get('line') as $line => $requestData) {
            foreach ($requestData as $input => $value) {
                $messages['line.' . $line . '.' . $input . '.required'] = 'The bloody ' . str_ireplace('_', ' ', $input) . ' on line ' . ($line + 1)  . '  is missing';
                $messages['line.' . $line . '.' . $input . '.min'] = 'The ' . str_ireplace('_', ' ', $input) . ' on line ' . ($line + 1)  . '  is must be a minimum of :min.';
            }
        }
        return $messages;
    }
}

One thing that is really irritating is that the error message array gets modified after it is returned and loses its order, so not all errors per line are grouped. But it's not that important.

Activity icon

Replied to Change Validation Message :attribute Placeholder For Array Inputs

@sti3bas and @tykus both these solutions look like great options.

I am quite new to Laravel, so could you just tell me where the code is dropped in.

@tykus I presume the closure goes like this, if so I still get the old message.

$validatedData = request()->validate([
    //...
    'line.*.description' => 'required',
    'line.*.retail_price' => function ($attribute, $value, $fail) {
        [$group, $position, $name] = explode('.', $attribute);
        $fieldName = Str::replace('_', $name);
    
        // required rule
        if (!$this->validateRequired($attribute, $value)) {
            $fail('The ' . $fieldName . ' on line ' . $position + 1 . ' is required.');
        }
    
    
        // min rule
        $minValue = 0;
        if (!$this->validateMin($attribute, $value, [$minValue])) {
            $fail('The ' . $fieldName . 'on line ' . $position + 1 . ' must be at least ' . $minValue);
        }
    },
    // ...
]);

I read https://laravel.com/docs/6.0/validation#using-closures but not sure that docs method works when using $validatedData = request()->validate([//**]);

Activity icon

Replied to Change Validation Message :attribute Placeholder For Array Inputs

Thanks @bobbybouwmann - the index is what I really need because the UI doesn't really lend itself to inline error messages.

Do you have any recommended reading on building it bespoke?

For now I will hack a JS string manipulation until I get the custom validation working.

Sep
10
4 months ago
Activity icon

Started a new Conversation Change Validation Message :attribute Placeholder For Array Inputs

I have a nested array of inputs being posted to a controller.

$validatedData = request()->validate([
    'line.*.image' => 'image|max:500',
    'line.*.description' => 'required',
    'line.*.retail_price' => 'min:0|required',
    'line.*.quantity' => 'min:1|required',
]);

When validation fails I receive an error message that looks like this:

The line.0.retail_price field is required.

How do I replace that to read something like:

The retail price on line 1 is required.

Sep
05
4 months ago
Activity icon

Replied to VueJS In My Blade Templates ( But Not SPA )

Thanks for clarification.

I actually watched that series up to episode 10, I think the answer to this question is in episode 15. ( https://laracasts.com/series/learn-vue-2-step-by-step/episodes/15 )

Activity icon

Replied to VueJS In My Blade Templates ( But Not SPA )

Thanks! I think I'm getting confused by Vue library docs where they reference implementation like this:

export default {
    name: 'app', // ??
    data: []
}

And I was expecting this:

new Vue ({
    el: '#app', // or #vue-section-1
    data: []
}

How and why are they different?

Activity icon

Started a new Conversation VueJS In My Blade Templates ( But Not SPA )

I want to make use of Vue.js in my Blade templates as a replacement for jQuery / plain JS.

How do I go about using Vue in sections of my Blade files rather than creating a full SPA?

Do I set a #app wrapper then bind it all to that or init the Vue component as separate instances of Vue?

<div id="app">
    <main>
        @yield('content')
    </main>
    <aside>
        @include('section.to.apply.vue.to')
    </aside>
</div>

<script>
var app = new Vue({
  el: '#app',
  data: {},
})
</script>

Or;

<div id="vue-section-1"></div>

<div id="vue-section-2"></div>

<script>
var vueSection1 = new Vue({
  el: '#vue-section-1',
  data: {},
})

var vueSection2 = new Vue({
  el: '#vue-section-2',
  data: {},
})

</script>

Is either fine? Or am I going about this the wrong way?

Any additional reading / videos on implementation would be just lovely. Thanks!

Sep
01
4 months ago
Activity icon

Replied to Where To Put Access Logic Vs Business Logic

I think you are right: QuoteRequestBidController is definitely the way forward. Just need to refactor and I think it will all fall into place.

Really appreciate the help.

Aug
31
4 months ago
Activity icon

Replied to Where To Put Access Logic Vs Business Logic

Thanks @stephens would you say that a Policy is the best practice here, despite it containing business logic?

Aug
30
4 months ago
Activity icon

Replied to Where To Put Access Logic Vs Business Logic

Thanks for your response, again @mikenewbuild.

One of the problems with using a Policy is that I don't know how to show an error to the user depending on what condition it fails on.

Is there a way to do that? Or in that case should I use a Controller?

Activity icon

Replied to Best Practice For $model->status Where Derived From Model Attributes

That's great, thanks @mikenewbuild. I will reorder as suggested.

Just a quick follow up:

If I am using those statuses expired, has_bids, etc in a Blade template and I want to use conditional CSS, icons and nice looking strings, what's the best method?

  • Blade component / include e.g. @include('_partials.statuses.quote-requests')
  • resources/lang file with translation {{ __( 'statuses.quote-requests.' . $quoteRequest->status ) }}
  • Or pass an array back from the model return ['css' => 'text-red-500', 'string' => 'Sorry this quote request has expired.']?
Activity icon

Started a new Conversation Best Practice For $model->status Where Derived From Model Attributes

I have two models Bid and QuoteRequest.

They have the relationships:

  • Bid->belongsTo('QuoteRequest')
  • QuoteRequest->hasMany('Bid')

The QuoteRequest->status is derived by knowing :

  • Is it expired?
  • Has it had any Bids attached to it?
  • Has a Bid been accepted?
  • Has a Bid been confirmed?

Could someone let me know if it's best practice to add this method to the QuoteRequest model:

public function status()
{
    if ( $this->isExpired() ) return 'expired';
    if ( $this->hasBids() ) return 'has_bids';
    if ( $this->hasAcceptedBid() ) return 'bid_accepted';
    if ( $this->hasConfirmedBid() ) return 'bid_comfirmed';
}

I did think to set a status in the database, but duplicates data because the status can be derived from the other columns / relationships.

Thanks for any help / criticism.

Activity icon

Started a new Conversation Where To Put Access Logic Vs Business Logic

I have the following business rules:

Only activated suppliers can create a Bid.

Suppliers can only create a Bid on an QuoteRequest when:

  • the QuoteRequest hasn't expired
  • they haven't already created a bid on the QuoteRequest
  • another bid hasn't been "accepted" for that QuoteRequest

Can someone tell where these rules belong. I did have them all in Policies/QuoteRequestPolicy.php but I feel like I am stretching the usage of a policy.

Should some of the logic be in the controller and/or the model?

Thanks!