4

I have a request for adding a show with a custom validation method in it that checks whether a show already exists that clashes with the date and time. If the method fails I want to say which show it clashes with in the validation error message.

class ShowStoreRequest extends Request {

    public function rules()
    {
        Validator::extend('time_clash_check', function($attribute, $value, $parameters)
        {
            list($day, $month, $year) = explode('/', $value);
            $date = $year.'-'.$month.'-'.$day;
            $start_time = $parameters[0];
            $end_time = $parameters[1];
            $show_id = $parameters[2];

            $query = Show::where('date', '=', $date)->where(function($q) use ($start_time, $end_time) {
                // show overlaps beginning of another show
                $q->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '>=', $start_time)
                      ->where('start_time', '<=', $end_time)
                      ->where('end_time', '>=', $end_time);

                // show is in the middle of the another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '<=', $start_time)
                      ->where('end_time', '>=', $end_time);

                // show overlaps the end of the another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '<=', $start_time)
                      ->where('end_time', '>=', $start_time)
                      ->where('end_time', '<=', $end_time);

                // show completely overlaps another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '>=', $start_time)
                      ->where('end_time', '<=', $end_time);
                });
            });

            if(!is_null($show_id)) {
                $query->where('id', '!=', $show_id);
            }

            $existing_show = $query->first();

            if(is_null($existing_show)) {
                return true;
            } else {
                return false;
            }
        });

        $rules = [
            'name' => 'required|max:255',
            'show_code' => 'required|alpha_num|min:10|max:11',
            'url_slug' => ['required', 'max:255', 'regex:/^[a-z0-9-_]+$/'],
            'youtube_url' => 'url',
            'name' => 'required|max:255',
            'date' => ['regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{2}/', 'time_clash_check:'.$this->start_time.','.$this->end_time.','.$this->route('id')],
            'start_time' => ['regex:/[0-9]{1,2}\:[0-9]{2}\:[0-9]{2}/'],
            'end_time' => ['regex:/[0-9]{1,2}\:[0-9]{2}\:[0-9]{2}/']
        ];
    }
}

So if time_clash_check fails I want to output the value of $existing_show->name in the error message to tell them which show it clashes with. How would I do this?

1 Answer 1

3

Add this into your request file:

class ShowStoreRequest extends Request {

    public $exists;

    public function rules()
    {
        Validator::extend('time_clash_check', function($attribute, $value, $parameters)
        {
            list($day, $month, $year) = explode('/', $value);
            $date = $year.'-'.$month.'-'.$day;
            $start_time = $parameters[0];
            $end_time = $parameters[1];
            $show_id = $parameters[2];

            $query = Show::where('date', '=', $date)->where(function($q) use ($start_time, $end_time) {
                // show overlaps beginning of another show
                $q->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '>=', $start_time)
                      ->where('start_time', '<=', $end_time)
                      ->where('end_time', '>=', $end_time);

                // show is in the middle of the another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '<=', $start_time)
                      ->where('end_time', '>=', $end_time);

                // show overlaps the end of the another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '<=', $start_time)
                      ->where('end_time', '>=', $start_time)
                      ->where('end_time', '<=', $end_time);

                // show completely overlaps another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '>=', $start_time)
                      ->where('end_time', '<=', $end_time);
                });
            });

            if(!is_null($show_id)) {
                $query->where('id', '!=', $show_id);
            }

            $existing_show = $query->first();

            if(is_null($existing_show)) {
                return true;
            } else {
                $this->exists = $existing_show->name;
                return false;
            }
        });

        $rules = [
            'name' => 'required|max:255',
            'show_code' => 'required|alpha_num|min:10|max:11',
            'url_slug' => ['required', 'max:255', 'regex:/^[a-z0-9-_]+$/'],
            'youtube_url' => 'url',
            'name' => 'required|max:255',
            'date' => ['regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{2}/', 'time_clash_check:'.$this->start_time.','.$this->end_time.','.$this->route('id')],
            'start_time' => ['regex:/[0-9]{1,2}\:[0-9]{2}\:[0-9]{2}/'],
            'end_time' => ['regex:/[0-9]{1,2}\:[0-9]{2}\:[0-9]{2}/']
        ];
    }
}

public function messages()
{
    return [
        'time_clash_check ' => $this->exists . ' has clashed'
    ];
}

Edit:

Okay, so, I worked out what the problem was. Here's the solution:

class ShowStoreRequest extends Request {

    public $exists;

    public function rules()
    {
        Validator::extend('time_clash_check', function($attribute, $value, $parameters)
        {
            list($day, $month, $year) = explode('/', $value);
            $date = $year.'-'.$month.'-'.$day;
            $start_time = $parameters[0];
            $end_time = $parameters[1];
            $show_id = $parameters[2];

            $query = Show::where('date', '=', $date)->where(function($q) use ($start_time, $end_time) {
                // show overlaps beginning of another show
                $q->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '>=', $start_time)
                      ->where('start_time', '<=', $end_time)
                      ->where('end_time', '>=', $end_time);

                // show is in the middle of the another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '<=', $start_time)
                      ->where('end_time', '>=', $end_time);

                // show overlaps the end of the another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '<=', $start_time)
                      ->where('end_time', '>=', $start_time)
                      ->where('end_time', '<=', $end_time);

                // show completely overlaps another show
                })->orWhere(function($q) use ($start_time, $end_time) {
                    $q->where('start_time', '>=', $start_time)
                      ->where('end_time', '<=', $end_time);
                });
            });

            if(!is_null($show_id)) {
                $query->where('id', '!=', $show_id);
            }

            $existing_show = $query->first();

            if(is_null($existing_show)) {
                return true;
            } else {
                $this->exists = $existing_show->name;
                return false;
            }
        });

        Validator::replacer('time_clash_check', function($message, $attribute, $rule, $parameters) {
            return str_replace(':variable', $this->exists, $message);
        });    

        $rules = [
            'name' => 'required|max:255',
            'show_code' => 'required|alpha_num|min:10|max:11',
            'url_slug' => ['required', 'max:255', 'regex:/^[a-z0-9-_]+$/'],
            'youtube_url' => 'url',
            'name' => 'required|max:255',
            'date' => ['regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{2}/', 'time_clash_check:'.$this->start_time.','.$this->end_time.','.$this->route('id')],
            'start_time' => ['regex:/[0-9]{1,2}\:[0-9]{2}\:[0-9]{2}/'],
            'end_time' => ['regex:/[0-9]{1,2}\:[0-9]{2}\:[0-9]{2}/']
        ];
    }
}

public function messages()
{
    return [
        'time_clash_check ' => ':variable has clashed'
    ];
}

That should fix the problem.

Sign up to request clarification or add additional context in comments.

9 Comments

That would output the name of the show I'm creating. I want to output the name of the existing show that it clashes with.
Sorry, I miss-understood. Updated my post. I set the $this->exists as $existing_show->name, but you'll need to correct the value if "name" is wrong. I was guessing.
I tried that approach before posting the question but I think the messages method gets run before the validation rule so the exists property doesn't exist at that point.
Hmm, what version are you using? Just tested it and it's working.
@geoffs3310 I've updated my post again. I've used a replacer, and it fixes the issue.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.