Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.x] Allow entries to be drafted without requiring validation #8919

Conversation

ryanmitchell
Copy link
Contributor

@ryanmitchell ryanmitchell commented Nov 2, 2023

This PR adds a new opt-in collection configuration option draft_without_validation which allows unpublished entries to be created without applying any validation rules.

Validation rules continue to be applied when the entry is published, but while its in an unpublished state they will not be run.

This can be useful if you are populating content but haven't yet been supplied all the information, or you haven't yet received assets.

I've left this PR as a draft just to get your thoughts, if it's a direction you like I will work on test coverage.

There seems to be a similar idea here: statamic/ideas#765

@edalzell
Copy link
Contributor

edalzell commented Nov 3, 2023

Love this, the validation on unpublished drives us crazy sometimes.

@jasonvarga
Copy link
Member

Thank you for this PR. I absolutely agree that there should be a way to save incomplete data.

However I'm not sure that completely bypassing validation is the right move.

I think what may be a more suitable solution is to have a way to define rules that should only be applied when publishing. I've two solutions that come to mind:

  1. Introduce a second config option on the field to define publish-only rules.

    CleanShot 2024-03-12 at 21 22 03

    validate:
      - 'max:3'
    validate_when_publishing:
      - required
      - 'min:2'
  2. Have some sort of special rule (thinking like the bail or sometimes rules) that would result in rules being ignored.

    CleanShot 2024-03-12 at 21 23 13

    validate:
      - 'max:5'
      - when_publishing
      - required
      - 'min:2'

    So maybe the presence of when_publishing will remove all the subsequent rules when editing a draft.

The second option is probably more feasible as we wouldn't need to pass two arrays all over the place. Also having this "publish only" option for non-entry blueprints becomes weird.

@jasonvarga jasonvarga closed this Mar 13, 2024
@edalzell
Copy link
Contributor

However I'm not sure that completely bypassing validation is the right move.

@jasonvarga why do you say that? When our clients start new entries they rarely want any validation at all, they only need to start getting data in, regardless of its correctness.

@jasonvarga
Copy link
Member

We still need some data integrity. When you save an entry, even a draft, stuff happens like fieldtype processing, events etc. The data should still be in the expected format. Fieldtypes may provide their own validation rules for this.

If you were using a traditional DB and you didn't have validation, you might end up putting invalid types into a column and you'd get query errors. There could also be the possibility of a security issue. (I don't know what yet, but I don't want to open it up as a possibility.)

I'd wager that most of the time, in a draft you only really care about leaving out required fields. You don't want to bypass all the validation rules.

This can be useful if you are populating content but haven't yet been supplied all the information, or you haven't yet received assets.

Stupid example but an integer field should still check that the submitted value is an integer. You shouldn't be able to submit a string just because it's a draft.

@edalzell
Copy link
Contributor

I'd wager that most of the time, in a draft you only really care about leaving out required fields. You don't want to bypass all the validation rules.

Agreed, and that might be the best implementation actually, if draft then replace the required with sometimes. Nothing new (in the blueprint) needed.

@jasonvarga
Copy link
Member

That's not how sometimes works. The sometimes rule prevents validation running on that field if it's missing from the request. When saving a draft the field will still be submitted.

I don't think just tweaking the required rule logic will work either though, because you could have some other rules that you might not care about in a draft, like min.

@edalzell
Copy link
Contributor

OK, I'm back to "please remove all rules when in draft". I'd rather start there (cuz that's the easiest), then put things back if folks need them

@jasonvarga
Copy link
Member

Respectfully, no. #8919 (comment)

If you really want, you can try this in the mean time:

Use the container to rebind the controller. In your update method, check if it's a draft, then rebind the validator to one that does nothing.

@ryanmitchell
Copy link
Contributor Author

ryanmitchell commented Apr 18, 2024

Somehow I missed this being closed and all this conversation, sorry for delayed replies.

I do think a good first step would be to allow required rules to be ignored when in draft mode - that would get around most of the issues. You still would have other validations, but they would only kick in if you choose to enter data in those fields, which is optional.

Would you be open to a new PR with that approach?

@sylvesterdamgaard
Copy link
Contributor

@ryanmitchell
I created a custom validator which handles the required rule nicely.
The only issue I encountered for this one is with revisions, as revisions are being "promoted" and bypasses the validation.

<?php

namespace App\Rules;

use Closure;
use Illuminate\Support\Facades\Validator;
use Illuminate\Contracts\Validation\ValidationRule;

class RequiredOnPublish implements ValidationRule
{
    /**
     * Run the validation rule.
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $published = request()->input('published');
        if ($published) {
            $validator = Validator::make(request()->all(), [
                $attribute => ['required'],
            ]);
            if ($validator->fails()) {
                $fail($validator->getMessageBag()->first($attribute));
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants