ms1987

Member Since 5 Years Ago

Experience Points
1,430
Total
Experience

3,570 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
0
Lessons
Completed
Best Reply Awards
2
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.

  • Community Pillar

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

Level 1
1,430 XP
May
04
1 week ago
Activity icon

Awarded Best Reply on Laravel - Inertia - Vue2 - Vuetify

DAMN! Nevermind!

Forgot to wrap my components in a v-app :-(

I figured i'd comment here, so that others might find it

Activity icon

Replied to Laravel - Inertia - Vue2 - Vuetify

DAMN! Nevermind!

Forgot to wrap my components in a v-app :-(

I figured i'd comment here, so that others might find it

Activity icon

Started a new Conversation Laravel - Inertia - Vue2 - Vuetify

Hi All,

I am currently in the process of setting up a project with laravel, inertia, vue2 and vuetify. All is working well, except for the fact that the colors for the vuetify theme are broken and i can't figure out why.

app.js

require('./bootstrap');

import { App, plugin } from '@inertiajs/inertia-vue'
import Vue from 'vue'
import vuetify from "./vuetify";

Vue.use(plugin)

const el = document.getElementById('app')

new Vue({
    vuetify,
    render: h => h(App, {
        props: {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: name => require(`./Pages/${name}`).default,
        },
    }),
}).$mount(el)

vuetify.js

import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.css'
import '@fortawesome/fontawesome-free/css/all.css'

Vue.use(Vuetify)

const opts = {
    icons: {
        iconfont: 'fa',
    },
    theme: {
        light: true,
        themes: {
            light: {
                primary: '#00379F',
                secondary: '#424242',
                accent: '#82B1FF',
                error: '#FF5252',
                info: '#2196F3',
                success: '#4CAF50',
                warning: '#FFC107',
            },
        },
    }
}

export default new Vuetify(opts)

package.json

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production"
    },
    "devDependencies": {
        "@fortawesome/fontawesome-free": "^5.15.3",
        "axios": "^0.21",
        "deepmerge": "^4.2.2",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "resolve-url-loader": "^3.1.3",
        "sass": "^1.32.12",
        "sass-loader": "^8.0.2",
        "vue-loader": "^15.9.6",
        "vue-template-compiler": "^2.6.12"
    },
    "dependencies": {
        "@inertiajs/inertia": "^0.8.7",
        "@inertiajs/inertia-vue": "^0.5.12",
        "vue": "^2.6.12",
        "vuetify": "^2.4.11"
    }
}

webpack.mix.js

const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js').vue()
    .sass('resources/scss/app.scss', 'public/css');

Sass compilation is working, because if i create a vue component with some scss in it, that works perfectly...

All help is greatly appreciated

Dec
27
4 months ago
Activity icon

Replied to Unique Validation On Related Model

@fcode , did it work? if so, can you mark the answer?

:-)

Activity icon

Replied to Github Actions Error.

what is the error you are getting then?

If you do the same process locally (clean install of your project) and run tests, does that fail also?

Activity icon

Replied to Github Actions Error.

The rm composer.local only now caught my eye... This is actually a very bad idea.

Your composer.lock file should always reside in your repo and be used in your CI. You want to install predictable dependency versions that you have implemented and tested.

By removing the composer.lock file, running composer install in your CI might install another version that matches within the version constraint that you defined in composer.json and thus yield unexpected results.

Dec
26
4 months ago
Activity icon

Replied to Uncaught ReferenceError: VueGoogleMaps Is Not Defined

That is hard for me or anyone to assess, as we dont have any config nor error logs.

I did caught my eye though that you are also having gmap-vue as a dependency? Why is that? I would suppose that this is redundant?

Maybe also share the code of the component that is actually using the map?

Which makes me wonder, is it the instantiation that fails (so the config in you app.js) (meaning that this gives you the error, even if you are on a page that does not have a map on it). Or do you only have the error when you actually have a map component?

this might provide insight into where the problem actually is.

Activity icon

Replied to Github Actions Error.

The best I can do for you, for the moment, is share a composer.json file that is working

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The Laravel Framework.",
    "keywords": [
        "framework",
        "laravel"
    ],
    "license": "MIT",
    "require": {
        "php": "^7.4",
        "fideloper/proxy": "^4.2",
        "fruitcake/laravel-cors": "^2.0",
        "globalcitizen/php-iban": "^4.0",
        "guzzlehttp/guzzle": "^7.0.1",
        "laravel/fortify": "^1.7",
        "laravel/framework": "^8.0",
        "laravel/tinker": "^2.0",
        "wildbit/postmark-php": "^4.0"
    },
    "require-dev": {
        "roave/security-advisories": "dev-master",
        "barryvdh/laravel-ide-helper": "^2.8",
        "facade/ignition": "^2.3.6",
        "fzaninotto/faker": "^1.9.1",
        "mockery/mockery": "^1.3.1",
        "nunomaduro/collision": "^5.0",
        "phpunit/phpunit": "^9.3"
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "autoload": {
        "psr-4": {
            "App\": "app/",
            "Database\Factories\": "database/factories/",
            "Database\Seeders\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\": "tests/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\Foundation\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    }
}

Some things that catch my eye

  • Have a look at your autoloading entries and compare those to mine
  • Choose a php version you want to stabilize on. (7 or 8 in this case).

Hope this helps

Activity icon

Replied to Github Actions Error.

Can you share the error you are receiving?

Activity icon

Replied to Uncaught ReferenceError: VueGoogleMaps Is Not Defined

Quickly compared it to a SPA in VueJS that I have, my main.js looks like this

import * as VueGoogleMaps from "vue2-google-maps";

Vue.use(VueGoogleMaps, {
  load: {
    key: process.env.VUE_APP_GOOGLE_API_KEY,
  }
});

Note that i am using an env variable to get the API key in.

Activity icon

Replied to What Is The Proper Way To Have A BelongsToMany / HasOne Field

Can you please mark @bestmomo reply as the anwser?

Activity icon

Replied to Has Been Blocked By CORS Policy: Response To Preflight Request Doesn't Pass Access Control Check: No 'Access-Control-Allow-Origin' Header Is Present On The Requested Resource.

Essentially the error states that your Access-Control-Allow-Origin header is missing ;-)

A quick google will take you here: https://stackoverflow.com/a/60996583/4875368

config\cors.php need a change in the allowed_origins_patternsarray

You could just whitelist all of them for now (only for dev purposes!)

Like so:

'allowed_origins_patterns' => ['*'],

Activity icon

Replied to Unique Validation On Related Model

Here we go :-) First you make a request that validates your input. It could look something like this

class DummyRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'question.options' => [
                new OptionsRule(),
            ]
        ];
    }
}

Then you create a new Rules object (you can do this via php artisan make:rule OptionsRule)

The rule could look something like this

class OptionsRule implements Rule
{
    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $allValues = collect($value);
        foreach ($value as $option) {
            $allValues->push($option['label']);
        }

        return $allValues->count() === $allValues->unique->count();
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The validation error message.';
    }
}

This is a very shallow implementation that will just loop over $value. $value is an array of all options for the question that came in via the request.

Here i just push all labels into a new collection and then compare the count of the entire collection (including possible duplicates) to the unique values (more information on the Collection methods in laravel can be found here: https://laravel.com/docs/8.x/collections#available-methods

My implementation is a bit shallow in the sense that i dont keep track of duplicated values. So rendering a descriptive message to the user might be a bit tricky now. This could easily be solved by keeping track of the duplicated values separately for example.

the message() method in the OptionsRule is responsible for rendering/returning the validation message to the user.

Hope that this can help getting you started ;-)

Activity icon

Replied to How To Submit Form Using Jetstream/Inertia

Glad to hear that you found a working solution.

Not sure what is in this.form, but i would try to stay close to Inertja's this.$inertia.post

Unless you have a clear reason not to do this.

Dec
25
4 months ago
Activity icon

Replied to Unique Validation On Related Model

Ah okay, that was not clear to me. The way I see it, you have 2 options.

  • You save the question first with a separate call, this way you have a question_id available, but at the cost of an addtional (ajax) request.
  • A better option to me, seems to create a custom rule (information here: https://laravel.com/docs/8.x/validation#custom-validation-rules). This rule would then take in the full options array (or even the full questions, depending on the structure of your request) and just loop over the options to validate that you dont have the same labels. I would then pay some attention to making sure that you can return a useful validation message to your frontend. so that you can provide some insight to your user on which label was duplicated.

Does this help?

Activity icon

Awarded Best Reply on Extend Jetstream Controller

Hi swist,

The simplest way to me, seems like this

  • Create a route (in web.php) that overwrites the Jetstream route that you mention here (same method, uri and name). This gives you the freedom to create a controller that does what you want (either create a plain new controller or extend from Laravel\Jetstream\Http\Livewire\LogoutOtherBrowserSessionsForm)
  • In app.php, make sure your RouteServiceProvider is located AFTER the JetstreamServiceProvider

never actually tried this myself, but this should do the trick just fine.

Activity icon

Replied to Unique Validation On Related Model

You can do this using a FormRequest validation indeed. Have a look here: https://laravel.com/docs/8.x/validation#rule-unique

I would try something like this (untested myself)

'options' => Rule::unique('options')->where(function ($query) {
    return $query->where('question_id', 1);
})
Activity icon

Replied to How To Extract Seeders From Mysql Dump File

Another approach that I love myself is to just import your .sql file once (locally). Use a tool like TablePlus and export your tables individually to json files. Then write one clever Db seeder that just reads the json files and inserts them into your db.

When done, just generate a new .sql file that is just your db structure (so no data) and rely on your db seeder and json files to seed your db.

Activity icon

Replied to How To Submit Form Using Jetstream/Inertia

Hi matheywparet,

Some things that catch me eye here. Make sure to post using the $inertia implementation.

this.$inertia.post

Secondly, though you dont show it here, make sure you php controller returns a correct Inertia Response. For example:

return Inertia::render('posts', ['data' => $data]);

Of course redirect responses etc would also work ;-)

Activity icon

Replied to Extend Jetstream Controller

Hi swist,

The simplest way to me, seems like this

  • Create a route (in web.php) that overwrites the Jetstream route that you mention here (same method, uri and name). This gives you the freedom to create a controller that does what you want (either create a plain new controller or extend from Laravel\Jetstream\Http\Livewire\LogoutOtherBrowserSessionsForm)
  • In app.php, make sure your RouteServiceProvider is located AFTER the JetstreamServiceProvider

never actually tried this myself, but this should do the trick just fine.

Activity icon

Started a new Conversation Laravel Stateless API Authentication Done Right

Dear all,

I have spent quite some time to try and figure out a correct and secure implementation of a Laravel stateless API. The purpose of this topic is two-fold. I find that there is so much incorrect and even downright dangerous blogposts out there, that I wanted to share my findings here. Secondly I do have some questions left, where I am looking for feedback/peer review.

Lets start off with my prerequisites when starting this journey.

  • I want my API to be fully stateless (no sessions!), so scaling it becomes a breeze. Just deploy it to another instance, add a loadbalancer to the mix (make sure you have a share database of course, and possibly a redis instance).
  • I did not want to use an Oauth approach, as my API will only couple with a SPA (Vue frontend) and it feels like an overkill to have a full Oauth flow for just one consumer and not machine-to-machine communication
  • I did not use Laravel Sanctum, as that is a session based implementation.

As an Implementation it goes like this:

  • Upon successful registration, I generate a JWT token for the user that is set in an encrypted cookie. The cookies has Same-Site: Strict , HttpOnly: true, Path: my-domain.example, Secure: true.
  • That JWT token contains only one thing: the UUID of the user (I choose to use UUID's everywhere instead of regular ID's)
  • When a request is made from the frontend to the API, the withCredentials: true flag makes sure that axios (or whatever http client you use), sends the cookie along with the request).
  • My Laravel API had a middleware that takes care of looking at the JWT token, making sure that it is valid, getting the user UUID from the JWT Token and performing the user lookup. (upon lookup, I have some checks in place to make sure that the user account is in the correct status etc). If all of this is successfull, I set the retrieved user via Auth::setUser()
  • I have a cors implementation in place that performs the necessary checks. Being a check on allowed methods (in my case, I allow for GET, PUT,POST, DELETE, PATCH and OPTIONS), a check that the request originated from a trusted origin, that it contains the right headers that I am expecting.

Security thoughts, opinions around this

  • I choose for a cookie based authentication flow, to make sure the frontend becomes immune to XSS, as my Javascript cannot access the cookie that contains my auth information. Is is really disturbing to see how many tutorials you find out there that actually advise you to store you JWT in localStorage. (I will share a link at the bottom of this post, that provides insights to why that is a horrible idea).
  • By making sure that my cookie is set tot httpOnly and SameSite strict, it helps protect me from CSRF attacks (more on that later).
  • By leveraging a CORS implementation, I can provide an additional layer of security by making sure that the requests are only made using methods I allow, as well as originate from origins I allow. Setting the SameSite to strict forces you to be specific about your origins. You can not use wildcard origins when using samesite strict.

Questions

  • Does this suffice in terms of CSRF protection? I find mixing information regarding the CSRF protection in this workflow.
  • The SameSite:strict behaviour confuses me a bit. When reading up on it, I find articles like this: https://blog.heroku.com/chrome-changes-samesite-cookie . Stating that when you are authenticated on my API (meaning you have a valid cookie), SameSite:strict should make sure that the cookie does not get sent along when I send a user from one domain to my domain. So as an example: somesite.com contains an < a > tag that has a link to mysite.com. When i try this, I do see that the cookie is being sent along. Which makes me wonder how secure it actually is. Because that would mean that you could potentially fabricate a url on somesite.com to perform a malicious action on mysite.com. I do understand that this is not CSRF in the pure sense (as you are not really submitting a form to mysite.com from somesite.com). But an AJAX request or < a > seems possible. Could someone shed some light on this for me?
  • Right now, my implementation sets a cookie with a lifetime that is in perfect sync with the TTL of my JWT token. Upon expiry of this lifetime, the user is being forced to re-login. Does someone have a propose how you could/would handle token refresh in a safe way? (by safe, i mean both safe in ajax usage (multiple calls might come in at once).

I notice that there is sooooo little (next to none that i could find) information about this kind of setup, that I would consider making a proper writeup/blog post somewhere once we can refine the approach a bit more here. Or Maybe even create a Laravel package for it (though I never really did that before).

I will close up here :-) Overall I am looking for (informed) opinions on this workflow and possible answers to my questions.

As promised, the link to the blogpost: https://dev.to/rdegges/please-stop-using-local-storage-1i04 (he is a bit fanatic maybe, but does make some very valid points).

Looking forward to opinions and answers about similar implementations by peers.