trevorpan

trevorpan

Member Since 1 Year Ago

Experience Points
48,210
Total
Experience

1,790 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
430
Lessons
Completed
Best Reply Awards
1
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 10
48,210 XP
Feb
16
3 days ago
Activity icon

Replied to Every Page Load Calls A Method That Is Supposed To Only Run Once

@mikemacdowell thank you for clarifying the JS issue I was facing.

Reread your reply and decided to watch this whole series in hopes of finding a technique https://laracasts.com/series/get-real-with-laravel-echo

Super cool stuff in that series but I didn't see:

You'd be better to have the time countdown on your server and the Event be executed at the point your server wants.

Do you know of a series on laracasts (or other resource) that covers your quote above?

Activity icon

Awarded Best Reply on Vue Components Are Not Working

not sure if this'll do it, but is necessary for my components to load properly

//above your new vue in app.js

const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Feb
14
5 days ago
Activity icon

Replied to Every Page Load Calls A Method That Is Supposed To Only Run Once

Hi thank you. @mikemacdowell

Maybe add a query string to the uri and check for it in the controller as a debug tool?

I'm not sure how to do the above. Do you know of a tutorial on that? This sounds like a great thing to have in my toolbox.

Just getting the component to update was a big challenge - especially the controller action updateBiddedStatus. I know telescope says the put method is used for [email protected].

I'll have to hunt around and see where it's referenced - however, it is only called when I load the page. (e.g. clicking a job page)

It seems to me like

this.$on('bidded', () => this.updateBiddedStatus());

needs to be limited to only ever firing once. Maybe instead of bidded there's another term used?

Activity icon

Started a new Conversation Every Page Load Calls A Method That Is Supposed To Only Run Once

Hi,

Was wondering if you could point out where this loads the updateBiddedStatus each time someone views the page.


    <div id="countdown">

        <slot :countdown="countdown">{{ until }}</slot>

        <div v-if="bidded" v-text="biddedText" v-bind:slug="slug">

        </div>

        <div v-else>
            <span>{{ remaining.days }} d, </span>
            <span>{{ remaining.hours }} h, </span>
            <span>{{ remaining.minutes }} m, </span>
            <span>{{ remaining.seconds }} s </span>
        </div>
    </div>

</template>


<script>

    import moment from 'moment';

    export default {

        props: {
            slug: '',
            until: String,
            biddedText: {
                default: 'This job has bidded.'
            },
        },

        data() {
            return {
                now: new Date(),
                countdown: '',
            }
        },

        created() {
            let interval = this.refreshEverySecond();

            this.$on('bidded', () => clearInterval(interval));
            this.$on('bidded', () => this.updateBiddedStatus());
        },

        computed: {
            bidded() {
                return this.remaining.total <= 0;
            },

            remaining() {
                let remaining = moment.duration(Date.parse(this.until) - this.now);

                if (remaining <= 0) {
                    this.$emit('bidded');
                }

                return {
                    total: remaining,
                    days: remaining.days(),
                    hours: remaining.hours(),
                    minutes: remaining.minutes(),
                    seconds: remaining.seconds()
                };
            },
        },

        methods: {

            refreshEverySecond() {
                return setInterval(() => {
                    this.now = new Date();
                }, 1000);
            },

            async updateBiddedStatus() {
                await window.axios.put(`/jobs/` + this.slug + `/updateBiddedStatus`);
            },
        }
    }
</script>

I added this condition in the following method but it seems to be called nonetheless as telescope says the DeadlineExpired event is fired and sends a mail. The goal is for the updateBiddedStatus to only run once - when the countdown timer gets to zero.

      public function updateBiddedStatus(Request $request, SlugJob $job)
        {
           // dd($job->complete);
            if ($job->complete === false) {
                DB::transaction(function () use($job) {

                    DB::table('jobs')
                        ->where([
                            ['id', $job->id],
                            ['bidded', '=', 0]
                        ])
                        ->update(array('bidded' => 1));
                });

                event(new DeadlineExpired($job));
            }
        }

Thank you ~

Jan
29
3 weeks ago
Activity icon

Replied to How To Create A Model And Payment With One Submit Button? (possibly Similar To A Shopping Cart And Payment Setup)

Has anyone made a shopping cart before?

Starting to think that may be the way to think about the problem.

Jan
28
3 weeks ago
Activity icon

Started a new Conversation How To Create A Model And Payment With One Submit Button? (possibly Similar To A Shopping Cart And Payment Setup)

// blade
                <form class="input-group" id="payment-form" action="/jobs/{{ $job->slug ?? '' }}/jobpostpayment" method="POST">

In this case, I'd like to have an offeror post a job and make a payment on the same page - at time of job (model) creation.

I've got another working charge the routes.web file is similar to this:

Route::post('jobs/{job}/jobpostpayment', '[email protected]');

However, as the job does not exist I tried using the ?? '' option to not crash the create page; this allows the page to render but fails with a 404 when hitting submit as the id has not yet been created.

Does this mean a two page form is in order? Is there a way to do it all on one page?

Have you created a temp_job table e.g. that sits in limbo until payment goes through? Then that's deleted and sent to the "real" jobs table for instance? Trying to get a strategy...

Jan
13
1 month ago
Activity icon

Replied to QR Code Alternatives

@bobbybouwmann you've got so many great tips.

It is pretty fancy but I think image in our apps matters a lot. I really like the laracasts videos widgets and recent improvements it just gives the site that polish..

The only thing I'm thinking is if you use a publicly available link or slug to generate the code someone could use your the qr api and 'copy' your code. Just a concern on scammers.

Maybe using a random generated number to create the code ??

Your last line - are you saying we can use the camera to scan a random number?

Jan
12
1 month ago
Activity icon

Started a new Conversation QR Code Alternatives

https://laracasts.com/discuss/channels/laravel/qr-code-generator https://laracasts.com/discuss/channels/laravel/qr-codes?page=1

I checked out the above posts. It appears even google deprecated their QR code api.

Is the main issue with using these the interpretation side?

The app I'm working on is kind of like ebay but it's construction materials so the buyer goes to the seller's business location to pick up their goods.

My goal is to generate a code of some sort (QR or otherwise) and when a person wins a bid a code is generated. When the buyer goes to pick up their construction materials the seller prints out a pdf with the code on it and the buyer uses their phone to verify the code through the laravel app.

The goal is to "verify" that the real seller is providing the goods and that the buyer has "accepted" them.

I could see just a random number generator working too but if you have any experience in this area I'd like to hear.

Activity icon

Awarded Best Reply on Using Axios.post To Update/trigger Database Transaction; Error: 0 Statements Were Executed

Spent a week reviewing js fundamentals and got this component to make the updates on the db table. For anyone who may come upon this later:

//Vuejs component
// use the v:bind=""
<template>
<div v-if="bidded" v-text="biddedText" v-bind:slug="slug">

...

</template>

...

// add an empty string on props:
slug: '',

...

created() {
    this.$on('bidded', () => this.updateBiddedStatus());
}

...

// I found this approach to work as I don't think creating an object was necessary as blade filled in the slug from the db.
async updateBiddedStatus() {
                await window.axios.put(`/jobs/` + this.slug + `/updateBiddedStatus`);
            },

In the blade file add:

<your component ... slug="{{ $job->slug }}"
Activity icon

Replied to Using Axios.post To Update/trigger Database Transaction; Error: 0 Statements Were Executed

Spent a week reviewing js fundamentals and got this component to make the updates on the db table. For anyone who may come upon this later:

//Vuejs component
// use the v:bind=""
<template>
<div v-if="bidded" v-text="biddedText" v-bind:slug="slug">

...

</template>

...

// add an empty string on props:
slug: '',

...

created() {
    this.$on('bidded', () => this.updateBiddedStatus());
}

...

// I found this approach to work as I don't think creating an object was necessary as blade filled in the slug from the db.
async updateBiddedStatus() {
                await window.axios.put(`/jobs/` + this.slug + `/updateBiddedStatus`);
            },

In the blade file add:

<your component ... slug="{{ $job->slug }}"
Jan
03
1 month ago
Activity icon

Replied to Using Axios.post To Update/trigger Database Transaction; Error: 0 Statements Were Executed

man, I keep getting this routing issue (from telescope):

PUT     /jobs/undefined/updateBiddedStatus  404     204ms   3s ago 
           updateBiddedStatus(job_id) {
                window.axios.put(`/jobs/${job_id}/updateBiddedStatus`).then(({ data }) => {
                    return data.job(job_id);
                });
            },

What is critical when you're sending a {job} from vue to a laravel route? Should a Vue single file component use props or the data()?

I feel like this is getting too complicated. It seems like all were trying to do is post the job_id to the route and the controller takes over??

Activity icon

Replied to Using Axios.post To Update/trigger Database Transaction; Error: 0 Statements Were Executed

Good morning, @spamhead2k gave that a shot - thank you.

Without the arrow the countdown timer does not keep updating; it just records the first second and stops. If you refresh it outputs that second.

So I tried without using the arrow on just this.updateBiddedStatus.

Could it have anything to do with the api routes? Just combing through that tutorial.

\routes\web.php
// Jobs
Route::resource('/jobs', 'JobsController', [
    'except' => ['updateBiddedStatus'] // is it necessary to except if it's a differently named method?
]);
Route::post('jobs/{job}/updateBiddedStatus', '[email protected]');

The other thought I have is is the jobs necessary ? I'm still pretty poor with js.

The good thing is that the job id does print in the jobId prop when you inspect. So I know it's calling the database in blade...

Jan
02
1 month ago
Activity icon

Started a new Conversation Using Axios.post To Update/trigger Database Transaction; Error: 0 Statements Were Executed

Hello ~

I'm modifying the countdown timer that was featured on laracasts. What I'd like to do is trigger this method on the controller:

        public function updateBiddedStatus($job)
        {
            DB::transaction(function () use($job) {

                DB::table('jobs')
                    ->where([
                        ['job_id', $job->id],
                        ['bidded', '=', 0]
                    ])
                    ->update(array('bidded' => 1));
            });

            event(new DeadlineExpired($job));

        }

Have used this tutorial: https://vuejsdevelopers.com/2018/02/05/vue-laravel-crud/ which has helped alot but it's not quite what I'm trying to do.

In blade, I call this Vue.component

    <div class="deadline">
            <h3>Deadline:</H3>
            <div class="countdown" id="countdown">
                <countdown until="{!! $job->deadline !!}" bidded-text="This job has bidded." job-id="{{ $job->id }}">
                    <template slot-scope="props">
                      <p v-text="props.until"></p>
                     </template>
                </countdown>
            </div>
            <div class="deadlineBackgroundBottom"></div>
    </div>
\Vue.component
<template>

    <div id="countdown">

        <slot :countdown="countdown">{{ until }}</slot>

        <div v-if="bidded" v-text="biddedText" v-bind:jobId="jobId">

        </div>

        <div v-else>
            <span>{{ remaining.days }} d, </span>
            <span>{{ remaining.hours }} h, </span>
            <span>{{ remaining.minutes }} m, </span>
            <span>{{ remaining.seconds }} s </span>
        </div>
    </div>

</template>


<script>

    import moment from 'moment';

    export default {

        props: {
            jobId: '',
            until: String,
            biddedText: {
                default: 'This job has bidded.'
            },

        },

        data() {
            return {
                now: new Date(),
                jobs: ''
            }
        },

        created() {
            let interval = this.refreshEverySecond();

            this.$on('bidded', () => clearInterval(interval));
            this.$on('bidded', () => this.updateBiddedStatus());
        },


        computed: {
            bidded() {
                return this.remaining.total <= 0;
            },

            remaining() {
                let remaining = moment.duration(Date.parse(this.until) - this.now);

                if (remaining <= 0) {
                    this.$emit('bidded');
                }

                return {
                    total: remaining,
                    days: remaining.days(),
                    hours: remaining.hours(),
                    minutes: remaining.minutes(),
                    seconds: remaining.seconds()
                };
            },
        },

        methods: {

            refreshEverySecond() {
                return setInterval(() => {
                    this.now = new Date();
                }, 1000);
            },

            updateBiddedStatus(jobId) {
                window.axios.post('/jobs/${job}/updateBiddedStatus').then(({ data }) => {
                    return data.jobs(jobId);
                });
            },
        }
    }
</script>

If you can see the error I'd really appreciate knowing. e.g. can you call (2) this.$on('bidded' ?

Dec
31
1 month ago
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Hi @bugsysha ,

Came across one little gotcha, that I finally got working.

    /**
     * Store a newly created resource in storage.
     *
     * @param $job
     * @return Response
     */
    public function store(SlugJob $job)

When you dd($job) it gives an instance of App\SlugJob (the extended eloquent model), so when you get to the next logic in the store method it tries to insert slug_job_id in addition to job_id. This was messing with the orders and charges and all sorts of things.

The trick? So simple.

// Job.php model

    public function bidReserves()
    {
        return $this->hasMany(BidReserve::class, 'job_id');
    }

Just specify the foreign key - it throws out slug_job_id on the App\SlugJob instance and proceeds as it originally did.

Thank you again!

Dec
29
1 month ago
Activity icon

Replied to Upgrading To 6.0; Email Verification Route Change When Using Auth::routes(['verify' => True]);

Don't know how I missed it. Thank you @bobbybouwmann

really looking forward to your "Laravel Secrets"!

Dec
28
1 month ago
Activity icon

Replied to Tuning Argon2id Hash Options To Your Server

Hi @braunson ,

Thank you; I certainly will swap those out where they occur.

I was hoping to see if someone also "tunes" their argon2id hash options to their server. From what I gather, the first example enclosed in the OP is something you can use to "tune" your bcrypt hash algorithm to the unique constraints of your own server; you run that on the server and that script will give you a value to use for bycrpt rounds (I think).

It's not an area I know much about...there's only three posts I found on laracasts.com with argon2id. Not too much to go on yet.

Activity icon

Replied to Upgrading To 6.0; Email Verification Route Change When Using Auth::routes(['verify' => True]);

Ha! thank you @bobbybouwmann .

I wish the docs mentioned that; I can see the {hash} was added to the route after running composer update.

Forgot about the php artisan route:list command. Even still, how do you locate the file where the routes are stored? I'm using phpstorm.

Activity icon

Started a new Conversation Tuning Argon2id Hash Options To Your Server

If you read up on https://www.php.net/manual/en/function.password-hash.php you get this code, but it appears to reference the bcrypt hash (unless I'm wrong).

<?php
/**
 * This code will benchmark your server to determine how high of a cost you can
 * afford. You want to set the highest cost that you can without slowing down
 * you server too much. 8-10 is a good baseline, and more is good if your servers
 * are fast enough. The code below aims for ≤ 50 milliseconds stretching time,
 * which is a good baseline for systems handling interactive logins.
 */
$timeTarget = 0.05; // 50 milliseconds 

$cost = 8;
do {
    $cost++;
    $start = microtime(true);
    password_hash("test", PASSWORD_BCRYPT, ["cost" => $cost]);
    $end = microtime(true);
} while (($end - $start) < $timeTarget);

echo "Appropriate Cost Found: " . $cost;
?>

On that page a comment mentioned this: https://tools.ietf.org/html/draft-irtf-cfrg-argon2-06#section-9.4

9.4. Recommendations: The Argon2id variant with t=1 and maximum available memory is recommended as a default setting for all environments. This setting is secure against side-channel attacks and maximizes adversarial costs on dedicated bruteforce hardware.

It's not clear if t=1 is time or threads.

//using php7.4 allows use of Argon2id
/*
    |--------------------------------------------------------------------------
    | Argon Options
    |--------------------------------------------------------------------------
    |
    | Here you may specify the configuration options that should be used when
    | passwords are hashed using the Argon algorithm. These will allow you
    | to control the amount of time it takes to hash the given password.
    |
    */

    'argon2id' => [
        'memory' => 1024,
        'threads' => 2,
        'time' => 2,
    ],

Do you have any experience here? How do you tune the algorithm options to your server?

Dec
27
1 month ago
Activity icon

Started a new Conversation Upgrading To 6.0; Email Verification Route Change When Using Auth::routes(['verify' => True]);

https://laravel.com/docs/6.x/upgrade#email-verification-route-change

The route path for verifying emails has changed from /email/verify/{id} to /email/verify/{id}/{hash}.

When I view routes\web.php I don't see the routes to change.

I've been looking all over for the file to make this change. Do you know where it is? I used php artisan make:auth in the 5.8 laravel, and have now upgraded to 6.0.

//web.php
Auth::routes(['verify' => true]);

if you use command+F7 in phpstorm it shows these two classes; when you open them they don't have the email routes.

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;

Thank you, Trevor

Dec
24
1 month ago
Activity icon

Awarded Best Reply on Implementing A User Interface For Roles & Permissions

Hi @jlrdw , thank you for having a look here.

It was simpler than I thought - just removing required from $this->validate(request(), lifted that validation error as you first pointed out. The html5 required has been added to the html select elements for added browser validation.

After thinking about it for a while I recognized this controller is not storing the roles/permissions it's using the html selects to check against known roles/permissions and if that clears then the roles/permissions are attached using eloquent in the backend.

Do you, or anyone else, see any security flaws in this approach?

/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate(request(), [
            'email' => 'string|email|max:255',
            'companyrole' => 'string|min:3',
            'companypermissions' => 'string|min:3',
        ]);

        $roleExists = Role::roleExists(request('companyrole'));
        $permissionExists = Permission::permissionExists(request('companypermissions'));

        if ($roleExists === true && $permissionExists === true) {

            $userExists = User::userExists(request('email'));
//            dd($userExists);
                if ($userExists) {

                    $companyHasAdministrator = Company::CompanyHasAdministratorRole(request('companyrole'));
    //                dd($companyHasAdministrator);
                    if ($companyHasAdministrator === false) {
//                        dd($userExists);
                        $role = Role::currentRole(request('companyrole'));
//                        dd($role);
                        $permission = Permission::currentPermission(request('companypermissions'));

                        $userExists->roles()->attach($role);
                        $role->givePermissionTo($permission);

                        flash('Thank you for adding roles and permissions.')->success();

                        return back();

                    } else {

                        flash('This company already has an administrator. Please select another role for that user.')->warning();

                        return back();
                    }

                } else {

                    flash('No one with that email exists. Would you please invite them in the Invitations Center below? After they accept you may add their roles and permissions.')->warning();

                    return back();

                }


        } else {

            flash('You have been reported to the FBI.')->warning();

            return back();
        }
Activity icon

Replied to Implementing A User Interface For Roles & Permissions

Hi @jlrdw , thank you for having a look here.

It was simpler than I thought - just removing required from $this->validate(request(), lifted that validation error as you first pointed out. The html5 required has been added to the html select elements for added browser validation.

After thinking about it for a while I recognized this controller is not storing the roles/permissions it's using the html selects to check against known roles/permissions and if that clears then the roles/permissions are attached using eloquent in the backend.

Do you, or anyone else, see any security flaws in this approach?

/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate(request(), [
            'email' => 'string|email|max:255',
            'companyrole' => 'string|min:3',
            'companypermissions' => 'string|min:3',
        ]);

        $roleExists = Role::roleExists(request('companyrole'));
        $permissionExists = Permission::permissionExists(request('companypermissions'));

        if ($roleExists === true && $permissionExists === true) {

            $userExists = User::userExists(request('email'));
//            dd($userExists);
                if ($userExists) {

                    $companyHasAdministrator = Company::CompanyHasAdministratorRole(request('companyrole'));
    //                dd($companyHasAdministrator);
                    if ($companyHasAdministrator === false) {
//                        dd($userExists);
                        $role = Role::currentRole(request('companyrole'));
//                        dd($role);
                        $permission = Permission::currentPermission(request('companypermissions'));

                        $userExists->roles()->attach($role);
                        $role->givePermissionTo($permission);

                        flash('Thank you for adding roles and permissions.')->success();

                        return back();

                    } else {

                        flash('This company already has an administrator. Please select another role for that user.')->warning();

                        return back();
                    }

                } else {

                    flash('No one with that email exists. Would you please invite them in the Invitations Center below? After they accept you may add their roles and permissions.')->warning();

                    return back();

                }


        } else {

            flash('You have been reported to the FBI.')->warning();

            return back();
        }
Dec
23
1 month ago
Activity icon

Replied to Implementing A User Interface For Roles & Permissions

It's not a multi-tenant. I would like to have the user select various roles/permissions from the dashboard.

Imagine ::::: company => has a user => who has a role => who then has permissions

I almost wonder if a pivot table should be a model???

The below seems like it would sabotage the attach() method and not really be using eloquent to it's finest.

//Here's a psuedo code.
$roleId = request('companyrole')->id;

$role = RolePermission::create([
    'role_id' => $roleId,
    'user_id' => auth->user()->id,
    ]);

any thoughts? how to escape the validation error and still use selects

Activity icon

Replied to Implementing A User Interface For Roles & Permissions

Hi @jlrdw ,

Well, I don't know what to say. I'd like someone who creates an account to be able to "claim" their company.

e.g. perhaps an employee finds BidBird and "invites" their boss. The boss may be older and not hip to the jive.

The roles and permissions, as noted in the form, are for the company. e.g. for the company to add or remove employees at will. The app will not want to dictate that or get in between those considerations.

It's entirely possible html selects are a dumb way to do this, but my OP is "Implementing a user interface for Roles & Permissions". Would really appreciate any ideas towards that end....

Activity icon

Replied to Implementing A User Interface For Roles & Permissions

hi, yea I've checked out their package, no views accompany the package.

My goal is for a user to have the option of choosing roles / permissions via html selects. I've been cracking my head to get to this point, but lack the experience.

The code I have checks the tables to see if the roles/permissions even exist. The goal is to prevent users from manipulating the values in the browser. If I'm not mistaken, you want this control.

Then it checks if a user via an html input for email exists.

If a user exists it checks if an administrator exists for that company, as only one admin can be on a company. Then it assigns the roles/permissions that the user has selected to that email (this can be themselves or someone else). It's pretty custom, but as Jeffrey said he likes to control this aspect of his site vs. a package.

Anyone else have an idea on how to implement this?

Activity icon

Replied to Implementing A User Interface For Roles & Permissions

still having an issue with this implementation.

From what I gather on all ACL, Roles & Permissions videos on laracasts you want to have the roles/permissions defined in the roles and permissions tables. Using tinker this is quite easy to attach roles/permissions - like the videos.

Using a dashboard and an input box and html selects gives an error:

    The email field is required.
    The companyrole field is required.
    The companypermissions field is required.

It feels like after validation the controller wants to create an object - and gives the error. How would you make it possible to attach the roles without throwing this error?

Here's the controller:

/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate(request(), [
            'email' => 'required|string|email|max:255',
            'companyrole' => 'required|string|min:3',
            'companypermissions' => 'required|string|min:3',
        ]);

        $roleExists = Role::roleExists(request('companyrole'));
        $permissionExists = Permission::permissionExists(request('companypermissions'));

        if ($roleExists === true && $permissionExists === true) {

//            $userEmailExists = User::userEmailExists(request('email'));
            $user = User::userExists(request('email'));

            if ($user) {

                $companyHasAdministrator = Role::CompanyHasCompanyAdministrator(request('companyrole'));

                if ($companyHasAdministrator === false) {

                    $role = request('companyrole');
                    $permission = request('companypermissions');

                    $user->roles()->attach($role);
                    $user->permissions()->attach($permission);

                    flash('Thank you for adding roles and permissions.')->success();

                    return back();

                } else {

                    flash('This company already has an administrator.')->warning();

                    return back();
                }

            } else {

                flash('No one with that email exists. Would you please invite them in the Invitations Center below? After they accept you may add their roles and permissions.')->warning();

                return back();

            }


        } else {

            flash('You have been reported to the FBI.')->warning();

            return back();
        }

    }
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

// Jobs route
Route::resource('/jobs', 'JobsController');

// Jobmedia route
Route::post('/jobs/media', '[email protected]')
  ->name('jobs.storeMedia');
    public function storeMedia(Request $request, Job $job)
    {
        $path = storage_path('medialibrary/temp/');

        if (!file_exists($path)) {
            mkdir($path, 0777, true);
        }

        $file = $request->file('file');

        $name = uniqid() . '_' . trim($file->getClientOriginalName());

        $file->move($path, $name);

        return response()->json([
            'name'          => $name,
            'original_name' => $file->getClientOriginalName(),
        ]);
    }

You're right again!

I can see this now, the addition of Job $job in this method was not required as it is governed by the public function store(Request $request, SlugJob $job). Is this an accurate assessment?

Have removed the Job $job from storeMedia to storeMedia(Request $request) as it originally was setup prior to implementing SlugJob. Also removed it from create().

Thank you for your expertise — Happy New Year, @bugsysha

Dec
22
1 month ago
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

On the jobs.create page there's a form with a file dropzone for uploading media - pdf, jpg, etc.. For some reason the not yet created $job->document was crashing the page giving this error: [document] was not a property on this collection.

Prior to implementing your solution with SlugJob the jobs.create page rendered just fine. After implementing - the page does not render, unless Job $job is type hinted in the controller.

It was strange to me, because the page is crashing before the form is submitted (when the jobs.create page is fetched) — but by putting an empty variable on the controller `public function create(Request $request, Job $job) it seems to prevent the crash.

Have you had experience where a not yet created variable causes a page to crash? I know this is related to our original post, as that's all I've been working on since it occurred. (I think future people may benefit by this gotcha being addressed - if possible)

Thank you again ~ @bugsysha

Dec
19
2 months ago
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Have been messing around with this for a bit. You are a life - saver. Thank you ~ @bugsysha

Not sure how this was getting tripped up; it was crashing the page saying [document] was not a property on this collection.

      @if(isset($job) && $job->document)
        var files =
          {!! json_encode($job->document) !!}
        for (var i in files) {
          var file = files[i]
          this.options.addedfile.call(this, file)
          file.previewElement.classList.add('dz-complete')
          $('form').append('<input type="hidden" name="document[]" value="' + file.file_name + '">')
        }
      @endif

This is a section for a dropzone file uploader. In the create page all I had was this:

//get
    /**
     * Show the step 1 Form for creating a new product.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        return view('jobs.create');
    }

// modified to
    /**
     * Show the step 1 Form for creating a new product.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request, Job $job)
    {
        return view('jobs.create', compact('job', 'request'));
    }

After implementing {slug} and {job} it was not working with just Request $request. I had to add Job $job to the create method and pass it to the view.

Before the SlugJob that was not the case. It's strange to me, as the view doesn't really have a job, this is the page to create one..?

Dec
15
2 months ago
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Thank you for hanging in on this, @bugsysha . I've found quite a few posts on the topic. Most notably this one: https://github.com/laravel/framework/pull/30471

That's a ways out though.

If I'm not mistaken the slug routes are needed to display the pages in this app, and the id's are needed to process charges and retrieve media. Not saying this is ideal but it's where the app's at at the moment.

Not sure why that would be a collection instance. Before the slug issue, I had quite a number of tests passing on this, where it was creating a model instance of BidReserve, Order, etc..storing the records.

// this action was changed from $job->id to:
<form id="payment-form" action="/jobs/{{ $job->slug }}/bidreserve" method="post">
    @csrf

...

    <button class="stripeButton">Bid Reserve</button>
</form>

Here's what I have in the BidReservesController.php

    /**
     * Store a newly created resource in storage.
     *
     * @param $job
     * @return Response
     * @throws ValidationException
     */
    public function store(Job $job)
    {
        $job = Job::Incomplete()
//            ->where('id', $job->id) // BUGSYSHA's added line 
//            ->orWhere('slug', $job->slug) // BUGSYSHA's added line 
            ->findOrFail($job);

  request()->validate([
            'amount' => 'required|numeric|min:1',
            'stripeToken' => 'required'
        ]);

        // Charging the bidder
        try {
            $bidReserve = $job->bidReserves()->create([
                'amount' => 500,
                'job_id' => $job->id,
            ]);

            $order = $bidReserve->complete($this->paymentGateway, request('stripeToken'), auth()->user()->id, $job, $bidReserve);

            return Route::redirect('jobs.show/{job->slug}')
                ->setStatusCode(201);
        } catch (PaymentFailedException $e) {

            return back()
                ->setStatusCode(422);

        }

I hope this helps out. If there's another snippet you need please let me know. I looked into the api, path()seems to be reserved for that exact function. Had played around with a slugPath() but it did not have any effect, and I was having a hard time figuring out where to call that - which is probably due to path() being reserved and I presume global...

Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Slug, slug, slug has slugged me.

I re-watched the below video, and have re-implemented this in the AppServiceProvider: https://laracasts.com/series/lets-build-a-forum-with-laravel/episodes/13

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        View::share('job', Job::all());
    }

It's giving an error here when doing a payment post, e.g.

select * from `jobs` where `slug` = '22' limit 1

or when switching:

select * from `jobs` where `bidded` = 0 and `jobs`.`id` = 'algolia-test' limit 1

I tried changing the calls from $job->id to $job->slug however it still gives errors such as: Method Illuminate\Database\Eloquent\Collection::bidReserves does not exist.

//Job.php model

    /**
     * Get a string path for the job
     *
     * @return string
     */
    public function path()
    {
//            return "/jobs/{$this->id}";

            return "/jobs/{$this->slug}";
    }

    /**
     * Get the route key for the model.
     *
     * @return string
     */
    public function getRouteKeyName(): string
    {
        return 'slug';
    }

If getRoutKeyName() is uncommented then the slug doesn't work.

I also added, as you mentioned, this to the JobsController

        $job = Job::where('id', $job->id)
            ->orWhere('slug', $job->slug)
            ->firstOrFail();

Below is a payment store function which attaches an order to the sale. One thing about slugs is that I didn't know to start using them immediately. A ton of logic is based on the $job->id.

Adding more difficulty, this app uses the Spatie Media-Library which bases the routing of media objects to the id. However, if in the browser a slug is present the media shows. So, I'm not sure if this is based on the View::share(). However, if you do a browser request such as bidbird.test/jobs/3 a 404 is returned. so I question if View::share() is working properly.

// BidReservesController.php
    /**
     * Store a newly created resource in storage.
     *
     * @param $job
     * @return Response
     * @throws ValidationException
     */
    public function store(Job $job)
    {
        $job = Job::Incomplete()
//            ->where('id', $job->id) // added line - may be removed
//            ->orWhere('slug', $job->slug) // added line - may be removed
            ->findOrFail($job);

It seems mostly to be a path() issue. I had even tried:

//Job.php model
 /**
     * Get a string path for the job
     *
     * @return string
     */
    public function path()
    {
        if ($this->id == 'job_id') {
            return "/jobs/{$this->id}";
        }
        elseif ($this->slug == 'job_slug'){
            return "/jobs/{$this->slug}";
        }

        //if ('job_id' == $this->id) {
        //    return "/jobs/{$this->id}";
        //}
        //elseif ('job_slug' == $this->slug){
        //    return "/jobs/{$this->slug}";
        //}
    }

but it was causing errors.

Do you have any more ideas? @bugsysha

Dec
14
2 months ago
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Hi @bugsysha ,

I'm trying to implement this and I believe the {id} is being found, as the button I've got

<div class="jobsbutton">
        <a href="/jobs/{{ $job->id }}">
            <button type="button" class="btn btn-job">Details</button>
        </a>
    </div>

is finding the right number (in addition to using slug). However, no data is pulled from the database. So, basically it shows the right id but cannot locate the data.

However, the routes seem to be all jacked up.

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        View::share('job_id', '$job');
    }

in the routes.web file:

// Jobs
Route::resource('/jobs', 'JobsController', ['except' => ['show']]);
Route::get('/jobs/{slug}', '[email protected]');
Route::get('/jobs/{job}', '[email protected]');

How do you make both {slug} and {job} work in the routes file? Thank you ~

Dec
08
2 months ago
Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Hi thank you @bugsysha ,

Have implemented this in the job.php

    /**
     * Get a string path for the job
     *
     * @return string
     */
    public function path()
    {
        return "/jobs/{$this->id}";
//        return "/jobs/{$this->slug}";
    }

Does the below conform to your approach?

<?php

namespace App;

use App\Job;

class SlugJob extends Job
{
    protected $table = 'jobs';

    /**
     * Get a string path for the job
     *
     * @return string
     */
    public function path()
    {
//        return "/jobs/{$this->id}";
        return "/jobs/{$this->slug}";
    }

    /**
    * Get the route key for the model.
    *
    * @return string
    */
    public function getRouteKeyName(): string
    {
        return 'slug';
    }

}

The issue facing now are these variables in the JobsController.php

public function show(SlugJob $job)
    {
        $downloads = $job->getMedia('document');

        $hasPayedBidReserve =
            auth()->user()
            ->bidReserves()
            ->where('job_id', $job->id)
            ->exists();

        $hasPlacedBid =
            auth()->user()
                ->bids()
                ->where('job_id', $job->id)
                ->exists();

        return view('jobs.show', compact('job', 'downloads', 'hasPayedBidReserve', 'hasPlacedBid'));
    }

'downloads', 'hasPayedBidReserve', 'hasPlacedBid' are dependent on the $jobId whereas job can use the slug. This is something i've wrestled withif you want several items to show on the page it seems like several controllers can make that happen.

In this case, if I move 'downloads', 'hasPayedBidReserve', 'hasPlacedBid' logic to the [email protected] they don't render. I'm guessing this is because the JobsController is the workhorse for showing the page?

Activity icon

Replied to Can You Use {id} For Some Logic And {slug} For Others?

Thank you, @tykus . I missed that article in the newsletter.

It's my first site, so unfortunately have a lot of balls down the field only to have someone (slugs) intercept!!!

Activity icon

Started a new Conversation Can You Use {id} For Some Logic And {slug} For Others?

Have just implemented slugs via the Laracasts videos and they work nicelyexcept for existing logic that uses {id}.

One example is the payment gateway:

http://bidbird.test/jobs//bidreserve

As you can see above the id is missing for the job.

//Job.php
/**
     * Get the route key for the model.
     *
     * @return string
     */
    public function getRouteKeyName()
    {
        return 'slug';
    }

//BidReservesController.php
    /**
     * Store a newly created resource in storage.
     *
     * @param $jobId
     * @return Response
     * @throws ValidationException
     */
    public function store($jobId)
    {
        $job = Job::Incomplete()->findOrFail($jobId);
...
//other logic

Can you use {id} for some logic and {slug} for others? Otherwise, it seems a tremendous amount of work needs to be done to fix this.

Dec
06
2 months ago
Activity icon

Started a new Conversation How To Assign An Algolia Media Path Using Spatie's Laravel-Media Package?

I've watched the laracasts videos on algolia and have managed to get the front end search functionality working.

The HasMedia trait has been added to the model I'm indexing. All the appropriate columns have been sent to the toSearchableArray(). However, I'm at a loss how to get the image associated with a post to display.

Am using vue component for the search functionality and have added this:

<img src=“{hit.imgUrl}” title=“{hit.name}” width=120 height=200 />

The above is based on algolia's examples. How exactly is this accomplished?

the toSearchableArray() doesn't make sense to include a url, as no one would search for a media object....

just gave this a shot to no avail.

<img src=“/ . '{{ {hit.objectID}->getMedia('document')->first()->getUrl('thumbnail') }}' ” title=“{hit.name}” width=120 height=200 />
Dec
01
2 months ago
Activity icon

Replied to Help With $this->actingAs($user)->post(...);

@sergiu17 I'm amazed you've watched 1,521 videos. One thousand, five-hundred and twenty-one videos!

Thought I was doin' ok at at 396...

Thank you ~

Activity icon

Replied to Help With $this->actingAs($user)->post(...);

that's simply amazing @sergiu17 ; I'm always over complicating things.

Route::post('/dashboard/companies', '[email protected]'); so, that's where all the magic comes from?

Activity icon

Replied to Help With $this->actingAs($user)->post(...);

hi, thank you.

tried that, your solution works! $this->get('dashboard') ->assertSee('BidBird');

When I try the $company->companyname it gives: ErrorException: Undefined variable: company This is without the temporary $company.

So, when we state a post route does the test know we're creating a company simply from the Routes/web.php?

Is it necessary to test with the company factory in scenarios like this?

Activity icon

Started a new Conversation Help With $this->actingAs($user)->post(...);

Alright, very close, but I find if I create a factory (with faker data) that handles all the fields the array second argument gets upset. A number of my other tests pass with the array data, but I'm not sure what's wrong with this scenario...

Really, there's no need to pass the second argument as the factory is creating everything, but I don't know how to handle that. I believe I have to use the post() in order for the database to store a company name, e.g. That's why the test failsfrom what I gather.

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

        $companyname = [
        'companyname' => 'BidBird'
        ];
//        dd($company->companyname);
//        $this->actingAs($user)
//            ->post('/dashboard/companies', $companyname);

        $this->actingAs($user)
            ->post('/dashboard/companies', [
                'companyname' => 'BidBird'
            ]);
//            ->assertRedirect('/dashboard')
//            ->assertStatus(200);

        $response = $this->get('/dashboard');
        $response->assertStatus(200);
        $response->assertViewIs('dashboard');
//        dd($company->companyname);
        $response->assertSee($company->companyname);
    }

gives the error: fails to assert .... </body>\n \n </html>\n ' contains "accusamus". so, clearly, $companyname is not posting. The faker accusamus is making it to the end.

When a test requires a post how to you $this->actingAs($user) ->post(...);

Thank you for any tips ~

Nov
29
2 months ago
Activity icon

Replied to Method `unique` Not Found In Illuminate\Support\Fluent

Great post, thank you.

Here's an interesting line to remember foreign key couple unicity.

In this case, I'm picturing users will work for a construction outfit and a few years later may go somewhere else/get fired, so I believe the many-to-many is ok.

Could also provide an opportunity for "power bidders" who after so many successful bids can be promoted to help other contractors, as a consultant, etc...Their profile could list the other companies they bidded for...

We'll see. I get lost in creative-land.

Thank you again!

Nov
28
2 months ago
Activity icon

Replied to Method `unique` Not Found In Illuminate\Support\Fluent

I'm telling you @drgreen so many little nuances. And you only find them in the trenches!!

Curious, on a pivot table are autoincrement id's necessary? In this particular case I don't believe it would make sense for a person to have multiple records with the company.

Primary Key is a unique key identifier for the row/record. So, you don't need to specify it to be unique as the primary itself is unique.

Does the Primary Key approach prevent duplicate rows?

Or does this just boil down to preference?

...

spent some more time here EDIT

The Primary Key does prevent duplicate entry:

Duplicate entry '20-2' for key 'PRIMARY'

Activity icon

Started a new Conversation Method `unique` Not Found In Illuminate\Support\Fluent

https://laracasts.com/series/laravel-6-from-scratch/episodes/31

Just watched the new vid above, and am looking again at a pivot table I created a while ago:

// My original approach
            $table->primary(['company_id', 'user_id']);

// the new video recommends this (in this scenario):
            $table->unique(['company_id', 'user_id']);
// I tried this:
    $table->primary(['company_id', 'user_id'])->unique();

but it yields this error in phpstorm Method 'unique' not found in Illuminate\Support\Fluent

What is the best solution for having a unique pivot relationship? Is the primary key designation useless in this scenario?

Nov
27
2 months ago
Activity icon

Replied to Implementing A User Interface For Roles & Permissions

Ok, so a form like:

//form code
<div class="form-group">
            
// backend code checks for email
    <input type="email" placeholder="email"> 

    <label for="companyrole">Company Role</label>
    <select class="form-control" id="companyrole">
        <option value="CEO">CEO</option>
        <option value="Employee">Employee</option>
    </select>

    <label for="companypermissions">Company Permissions</label>
    <select class="form-control" id="companypermissions">
        <option value="Can view all financials">Can view all financials</option>
        <option value="Can bid">Can bid</option>
    </select>

    <button id="submit" type="submit">Add role/permissions</button>-
</div>

In this case above, the check on email...it seems like the person should have to accept if their email isn't from the same domain?

Activity icon

Replied to Implementing A User Interface For Roles & Permissions

sorry I missed your post, @jlrdw

Mainly, I'm interested in the user interface. e.g. what's it look like to add a role, permission?

Activity icon

Started a new Conversation Implementing A User Interface For Roles & Permissions

https://laracasts.com/series/whats-new-in-laravel-5-1/episodes/16

I've got a decent handle on creating the tables, etc. However, how have you solved this issue?

The goal on the dashboard is for an admin to be able to add a user to a role/permission. e.g. on this site a company owner may want to have 3 employees be able to bid on jobs. I want the owner to have control; if a user is fired or leaves the company the owner/admin can delete their roles/permission on that company without the website admin from having to do all this tedious work.

If a user is a member of the site does the admin type an email and then this is saved to the roles/permissions table? Then do you display these company users to the company admin? Like a looped list.

The dashboard currently has an invitation form which allows an existing user to invite others (there's a method which checks if an email already exists); it seems like this should stay vanilla and then only someone who is a user can be added for Roles & Permissions.

Trying to wrap my head around this problem.

Nov
18
3 months ago
Activity icon

Replied to Footer Contact Form

good morning @cronix

Ahh, never saw the first url part before. I've used the name() plenty of times. Great tip.

Thank you!

Nov
17
3 months ago
Activity icon

Replied to Footer Contact Form

@snapey

Route::post('contact', ['url' => 'contact', 'uses' => '[email protected]'])->name('contact.post');

Why is this working?

Does the ['url' => 'contact' .. line act as a wildcard for any page on the site?

Just implemented this on my own site, and it's fab.

Nov
16
3 months ago
Activity icon

Replied to Vue Components Are Not Working

not sure if this'll do it, but is necessary for my components to load properly

//above your new vue in app.js

const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Activity icon

Replied to Why Is Link To Page Section /#footer Not Linking?

A friend suggested a doing a javascript function to make it scroll smooth. I saw a few examples on stack that seemed a bit lengthy.

html, body {
...
scroll-behavior: smooth;
...
}

That did a pretty nice job, for just one line.

Nov
15
3 months ago
Activity icon

Replied to Why Is Link To Page Section /#footer Not Linking?

@snapey does it again!!!

Thank you, this was actually hard to search for.