Perdanjam

Perdanjam

Member Since 8 Months Ago

Experience Points
25,100
Total
Experience

4,900 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
227
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start your 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-in-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 Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist 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 6
25,100 XP
Aug
06
1 week ago
Activity icon

Replied to Sanctum Cors Issue

I use Laragon which sets up domain aliases to {folder-name}.test. However, it's also accessible at localhost/{folder-name}/public.

So I set my axios baseURL like this: axios.defaults.baseURL = "http://localhost/vue-spa/public";

Then I set my SESSION_DOMAIN to localhost and SANCTUM_STATEFUL_DOMAINS to localhost:8080.

Then in the cors config I added any and all routes that will access the backend.

'paths' => ['api/*', 'login', 'logout', 'sanctum/csrf-cookie', 'home', 'dashboard']

Jul
29
2 weeks ago
Activity icon

Replied to How To Update Relationship?

I may be over simplifying it but you could submit all the urls using the <input name="urls[]"> syntax to get an array and loop through it.

Something like:

    public function update(Request $request, Game $game)
    {
        $urls = $request->get('urls');

        for ($i=0; $i < count($game->urls); $i++) { 
            $game->urls[$i]->update([
                'url' => $urls[$i]
            ]);
        }
    }
@forelse($game->urls as $url)
    <input type="text" name="urls[]" value="{{$url->url}}" >
@empty
    No links
@endforelse
Jul
27
2 weeks ago
Activity icon

Commented on Route Custom Keys With Scoping

I experienced some weird behaviour where this didn't work until I put the getRouteKeyName() method in my model. Then it worked, and still works after deleting the getRouteKeyName() method.

The slug is {user:username} and username is a unique() column. Not sure if that's anything to do with it but something to watch out for.

Jul
26
2 weeks ago
Activity icon

Replied to Eloquent Relationships Between Different Types Of User (based On Role)

Thanks man. It's great to have another dev's insight.

I will give it a shot at writing something more readable using only a User model.

If I come up with something I'm happy with I will comment it here to help others.

Activity icon

Replied to Eloquent Relationships Between Different Types Of User (based On Role)

@bobbybouwmann Thanks for reading/ replying.

I have the roles set up as many-to-many relationships, I actually implemented it exactly as Jeffrey explains here https://laracasts.com/series/laravel-6-from-scratch/episodes/54

I'm just confused about relationship clashes, eg:

// App\User
// Teacher (User) has many classes.
    public function classes()
    {
        return $this->hasMany(Group::class, 'teacher_id');
    }

// Student (User) belongs to many classes.
    public function classes()
    {
        return $this->belongsToMany(Group::class);
    }

As these are all just Users, is it acceptable to rename the methods (to avoid a clash) and peform a check before the relationships like:

    // App\User
    // Teacher has many classes.
    public function classesOfStudents()
    {
        if ($this->hasAnyRole(['teacher', 'admin'])) {
        return $this->hasMany(Group::class, 'teacher_id');
        }
    }

    // Student can be in many classes.
    public function studyGroups()
    {
        if ($this->hasAnyRole(['student'])) {
            return $this->belongsToMany(Group::class);
        }
        
    }
Activity icon

Started a new Conversation Eloquent Relationships Between Different Types Of User (based On Role)

First off, apologies, because I can see this topic is discussed on the forum pretty regularly. However I'm struggling to find an answer that can clarify the best way to go about this for me.

I have roles set up. My roles are :

Admin, Teacher, Student.

They are all just Role models linked to Users in role_user table.

Ultimately I want to set up relationships between different types of Users.

Teacher belongsToMany Students  
Students belongsToMany Teachers

I'll also have other models like Group which are different per Role.

Teacher hasMany Groups
Student belongsToMany Groups

Is it possible to set these relationships up when they are all on the Users table?

I have a feeling I should either 1. be extending the User model for this, or 2. maybe morphing a type of Role to the User (I'm not too familiar with polymorphism).

Can anyone push me in the right direction?

Jun
17
1 month ago
Activity icon

Replied to Laravel Livewire / Alpine Multiple Select, Livewire Not Refreshing

I have gone with a different approach. I am just doing wire:click="selectSpecies($event.target.innerText)" instead and I'll do the validation logic on the backend.

Activity icon

Replied to Laravel Livewire / Alpine Multiple Select, Livewire Not Refreshing

I've made a short video showing the problem a bit clearer. You can see how the {{ print_r($species) }} only changes when I click on the select options. https://imgur.com/a/vT1ljLK

But I will hide the select, so I need this functionality to come from clicking the real dropdown.

Activity icon

Started a new Conversation Laravel Livewire / Alpine Multiple Select, Livewire Not Refreshing

So I have a select with options, this is hidden from the DOM. When options are selected with javascript (using Alpine), the Livewire data is not updated.

<select id="select" x-cloak multiple wire:model="species">
        <option value="Carp">Carp</option>
        <option value="Trout">Trout</option>
        <option value="Pike">Pike</option>
        <option value="Catfish">Catfish</option>
    </select>

However, if I unhide the <select> and physically click the options, the Livewire binding is updated (as intended). I've tested this using blade echo.

My question is, how can I keep the <select> hidden and still update the Livewire data with javascript?

I've been reading Livewire/ Alpine docs but can't figure it out. I'm guessing it's because wire:model is probably driven by the click event (like v-model), but even if I select the <option> in the console and call .click(), this doesn't work either.

Any ideas?

Jun
16
1 month ago
Activity icon

Awarded Best Reply on Eloquent One To One, HasOne / BelongsTo Relationship Only Readable One-way?

I found my bug! I was previously storing address directly on the Fishery model as a JSON column. So I had protected $casts = [ 'address' => 'array' ] still on my Fishery Model. Removing this solved the problem.

So, to make this SEO friendly for anyone searching: If your hasOne relationship or belongsTo one to one relationship is returning null. Be sure to check your $casts in case you are migrating from a table column to a new model and forgot to delete it.

Activity icon

Replied to Eloquent One To One, HasOne / BelongsTo Relationship Only Readable One-way?

I found my bug! I was previously storing address directly on the Fishery model as a JSON column. So I had protected $casts = [ 'address' => 'array' ] still on my Fishery Model. Removing this solved the problem.

So, to make this SEO friendly for anyone searching: If your hasOne relationship or belongsTo one to one relationship is returning null. Be sure to check your $casts in case you are migrating from a table column to a new model and forgot to delete it.

Activity icon

Replied to Eloquent One To One, HasOne / BelongsTo Relationship Only Readable One-way?

Hi @kalemdzievski thanks for the response, in fact I originally set up my factories and seeder like the way you've said.. I just changed back to it and the problem is still there.

In Tinker \App\Fishery::find(1)->address returns null, but Address::where('fishery_id', 1)->get() returns the correct model (in a collection).

This is still the case whether I run the following code or not.

            $fishery->address()->save(Address::where('fishery_id', $fishery->id)->first());
        });

I feel like the following code is the kind of thing I am missing, but this causes an error when running:

            $table->foreign('id')->references('fishery_id')->on('addresses');

I am using laravel-frontend-presets / tall for the ui scaffolding, could this be interfering at all?

Jun
15
1 month ago
Activity icon

Started a new Conversation Eloquent One To One, HasOne / BelongsTo Relationship Only Readable One-way?

I am only able to read the belongsTo relationship ($address->fishery) to return the model. The hasOne ($fishery->address) is returning null. I think it might be due to the way I'm seeding.

Can anyone help? I have the following set up:

class Fishery extends Model
{
    public function address()
    {
        return $this->hasOne(Address::class);
    }
}
class Address extends Model
{
    public function fishery()
    {
        return $this->belongsTo(\App\Fishery::class);
    }
}

and the foreign key is in the address table:

    public function up()
    {
        Schema::create('addresses', function (Blueprint $table) {
            $table->id();
            $table->string('line_one');
            $table->string('line_two')->nullable();
            $table->string('town');
            $table->string('county');
            $table->string('post_code');

            $table->unsignedBigInteger('fishery_id');
            $table->foreign('fishery_id')->references('id')->on('fisheries');
            $table->timestamps();
        });
    }

in my seed:

    public function run()
    {
        factory(Fishery::class, 20)->create();

        factory(Address::class, 20)->create();

        Fishery::all()->each(function($fishery) {
            $fishery->address()
		->save(Address::where('fishery_id', $fishery->id)
->first());
        });

    }

and finally, address factory:

$factory->define(Address::class, function (Faker $faker) {
    return [
        'line_one' => $faker->streetAddress,
        'town' => $faker->city,
        'county' => $faker->state,
        'post_code' => $faker->postcode,
        'fishery_id' => $faker->unique()->numberBetween(1,20)
    ];
});
Jun
14
2 months ago
Activity icon

Commented on Fetch Game Information From The IGDB API

Nice episode. Inside withOptions, how did you know to label the apicalypse query as 'body' ? I feel like that would've been taken me hours 'in the wild'

Jun
11
2 months ago
Activity icon

Awarded Best Reply on Why Is My Validation 'required|file' Passing Even When I Pass A String?

Ok so to anyone who stumbles on to this, my problem was twofold.

  1. Laravel returns a redirect response with session errors from failed HTTP validation. So the 422 status would not be expected in this case, a redirect response would be.

  2. Using the following code it works. This is how session errors are generated and stored for arrays. I found this by dd(Session::all()); in the test after the post().

$response = $this->post('/games/create', [
            'title' => 'valid string',
            'audio' => ['string'],
            'sentence' => ['string']
        ]);

        $response->assertSessionHasErrors(['audio.0']);
Activity icon

Replied to Why Is My Validation 'required|file' Passing Even When I Pass A String?

Ok so to anyone who stumbles on to this, my problem was twofold.

  1. Laravel returns a redirect response with session errors from failed HTTP validation. So the 422 status would not be expected in this case, a redirect response would be.

  2. Using the following code it works. This is how session errors are generated and stored for arrays. I found this by dd(Session::all()); in the test after the post().

$response = $this->post('/games/create', [
            'title' => 'valid string',
            'audio' => ['string'],
            'sentence' => ['string']
        ]);

        $response->assertSessionHasErrors(['audio.0']);
Activity icon

Replied to Why Is My Validation 'required|file' Passing Even When I Pass A String?

Changing my post data to below but the error is still there:

$this->post('/games/create', [
            'title' => 'valid string',
            'audio' => ['not-audio'],
            'sentence' => ['valid string']
        ])->assertStatus(422);
Activity icon

Started a new Conversation Why Is My Validation 'required|file' Passing Even When I Pass A String?

In my test I'm posting a string:

$this->post('/games/create', [
            'title' => 'valid string',
            'audio.*' => ['not-audio'],
            'sentence.*' => ['valid string']
        ])->assertStatus(422);

In my controller validation I'm requiring a file:

$request->validate([
            'title' => 'required|string',
            'audio.*' => 'required|file',
            'sentence.*' => 'required|string'
        ]);

But the data is accepted, can anyone see what I'm doing wrong?

Activity icon

Replied to Dynamic Gate Abilities

There is now a video on this exact situation here: https://laracasts.com/series/laravel-6-from-scratch/episodes/54

Be sure to only return true if the check passes:

    public function boot(GateContract $gate)
    {
        parent::registerPolicies($gate);

        $gate->before(function($user, $ability) use ($gate){
		if ($user->hasPermission($ability)) {
            		return true;
		}
        });
   }
Jun
10
2 months ago
Activity icon

Awarded Best Reply on Authorization Exception Testing VS 403 Status

For anybody reading this, I have just used

$this->post('url', compact('title')->assertStatus(403);

without saving the response to $response, just stringing on to the get() and it works fine now...

Activity icon

Replied to Authorization Exception Testing VS 403 Status

For anybody reading this, I have just used

$this->post('url', compact('title')->assertStatus(403);

without saving the response to $response, just stringing on to the get() and it works fine now...

Activity icon

Started a new Conversation Authorization Exception Testing VS 403 Status

I've just added a roles and abilities system as detailed here: https://laracasts.com/series/laravel-6-from-scratch/episodes/54

Basically we add a global Gate::before in the AuthServiceProvider boot method, and check for the abilities associated with the Role, and by proxy the User.

public function boot()
    {
        $this->registerPolicies();

        Gate::before(function($user, $ability) {
            if ($user->abilities()->contains($ability)) {
                return true;
            }
        });
    }

HOWEVER, normally in testing I would do assertStatus(403), but now I find myself doing $this->expectException(\Illuminate\Auth\Access\AuthorizationException::class);

Is this a safe workaround? ... it doesn't feel right (yet?). I don't like the the assertion before the code, it also means that particular test is limited to that assertion, so I have to create more tests than I normally would.

Does anyone have any strong views on this? Is there a better way to test-drive this scenario?

See my example below:

/** @test */
    public function gamesCannotBeCreatedByGuests()
    {
        $this->withoutExceptionHandling();
        $user = factory(User::class)->create();
        $this->actingAs($user);

        $title = 'A random title for the database!';

        $this->expectException(\Illuminate\Auth\Access\AuthorizationException::class);

        $response = $this->post('/games/create', compact('title'));
    }
Jun
07
2 months ago
Activity icon

Started a new Conversation Ajax Response String, Not Json, Not Xml, Not Sure How To Read It?

I am trying to get content that comes from an ajax request. Normally I would query the ajax url directly, but I have no idea how to read the response. Here's the response https://imgur.com/fhIkhbE I am expecting some Chinese characters in the response, but not these ones, this just gibberish. Chinese characters are multibyte, and I think the response gets run through some other javascript file to decipher it. But the javascript file is not readable to a human.

So I have 2 questions,

  1. Does anyone know how to decipher this response?
  2. Is it possible to web scrape a page after the ajax has loaded?
Apr
03
4 months ago
Activity icon

Commented on WYSIWYG

I've got a bug when trying to render stored content. https://stackoverflow.com/questions/61010472/trix-editor-not-rendering-stored-content

Anyone got any ideas?

Mar
29
4 months ago
Activity icon

Replied to Storage Link Not Loading Image After Symlink

@sanjay23 did you ever solve this? I am having the same issue right now. Any image paths coming from the symbolic link are showing 404

Feb
10
6 months ago
Activity icon

Replied to $children Changing Order When Changing Slot, How To Maintain Original Order?

That worked! Thanks so much. I'm a bit confused because I set the key inside the tabs component

<li
          v-for="(tab, i) in tabs"
          :key="i"
>

However that didn't do anything to solve the bug.

But your suggestion works.

Is the :key in the component template related to the key="" in the root template?

Feb
09
6 months ago
Activity icon

Started a new Conversation $children Changing Order When Changing Slot, How To Maintain Original Order?

I can't figure out where this bug comes from. The child components are re-ordering and getting modified when I change the slot they appear in. You can see the live demo at www.perryjames.uk

Just click 'switch nav' in the top right.

Essentially I have two <slot> with the same name/content but I only display one, the bug occurs when triggering the switch between slots.

<template>
      <slot name="content" v-if="placement === 'top'"></slot>
    </template>

<ul>
//nav bar code with v-for on array of $children
</ul>

<template>
      <slot name="content" v-if="placement === 'bottom'"></slot>
 </template>

and then in the parent:

<tabs v-slot:content :placement="contentLocation">
      <tab title="About" :selected="true">
        <profile></profile>
      </tab>
      <tab title="Laravel">
        <laravel></laravel>
      </tab>
      <tab title="Vue">
        <vue></vue>
      </tab>
      <tab title="Other Projects">
        <others></others>
      </tab>
    </tabs>

The method code is:

methods: {
    switchNav() {
      this.contentLocation == "top"
        ? (this.contentLocation = "bottom")
        : (this.contentLocation = "top");
    }
  }

Any pointers would be appreciated!

I think this could be due to the way Vue renders components in $children... but I cannot find anyone else having this bug elsewhere, maybemy whole structure is wrong..?