<p>You can check if an element is valid by calling <a href="https://www.yiiframework.com/doc/api/2.0/yii-base-model#validate()-detail" rel="nofollow noreferrer">Entry::validate()</a> yourself. The problem is that if you do that inside the <code>EVENT_BEFORE_VALIDATE</code> hook, it <em>might</em> cause an infinite loop (not sure if Yii2/Craft are smart enough to detect this, may be worth testing). However, it should work fine if you execute the validation in an <code>EVENT_BEFORE_SAVE</code> hook:</p>
<pre class="lang-php prettyprint-override"><code>Event::on(
    Entry::class,
    Element::EVENT_BEFORE_SAVE,
    function (ModelEvent $e) {
        $entry = $e-&gt;sender;
        // bail if the entry is not valid
        if (!$entry-&gt;validate()) return;

        // now we can safely execute the API call since the entry is valid
    },
);
</code></pre>
<p>If the validation fails, you don't have to do anything else because the Craft will prevent saving the entry anyway. If the validation succeeds, you know the regular fields are valid and can continue with your API call. If something goes wrong there, you can set <code>$e-&gt;isValid = false</code> and it will prevent the entry from saving, same as in the <code>EVENT_BEFORE_VALIDATE</code> hook.</p>
<p>Now there might be some edge cases, for example if you have another hook modifying the entry to make it valid AFTER your hook has run. But I doubt that will make a difference in practical terms.</p>

CC BY-SA 4.0
2021-06-17T08:42:36.260Z
2021-06-17T08:42:36.260Z
MoritzLost
<p>I am trying to validate entries on Save in a Module.</p>
<p>My specific use case requires that the Entry validation - on failure to validate will return user to form with field errors.</p>
<p>On successful validation I want to use that information to call an API with the field information and if all goes well I want to save - otherwise (e.g. API error) - I want to cause validation failure and show specific errors on the form.</p>
<p>From My understanding: the events occur in the following order:</p>
<p>EVENT_BEFORE_SAVE, EVENT_BEFORE_VALIDATE, EVENT_AFTER_VALIDATE, EVENT_AFTER_SAVE</p>
<p>I know I can do this:</p>
<pre><code>    Event::on(
        Entry::class,
        Entry::EVENT_BEFORE_VALIDATE,
        function(ModelEvent $event) {
            $entry = $event-&gt;sender;
            //if send to api failure
            $entry-&gt;addError('field','api failed');
            $event-&gt;isValid=false;

        }
    );
</code></pre>
<p>It allows me to invalidate the save but - It does so before the regular fields are validated.
My desire here is that I can protect some bad inputs to the API using crafts validation features and then send to API and then act upon its result.</p>
<p>From what I have seen - EVENT_AFTER_VALIDATE always runs even if the field validation failed.</p>
<p>So It made sense to me that I could check $event-&gt;isValid in EVENT_AFTER_VALIDATE so my API hit would only happen on successful validate</p>
<p>I have discovered that EVENT_AFTER_VALIDATE is receiving an Event instead of a ModelEvent
Which means $event-&gt;isValid cannot be used to invalidate the save or check if the validation was successful. I've tried switching this around to no avail.</p>
<p>I seem to be able to use $entry-&gt;addError() to invalidate the save.
I'm just missing how to find out how the regular validation went..</p>
<pre><code>    Event::on(
        Entry::class,
        Entry::EVENT_AFTER_VALIDATE,
        function(Event $event) {
            $entry = $event-&gt;sender;
            //if ($event-&gt;isValid) {
                //if send to api failure
                $entry-&gt;addError('field','api failed');
            //}
        }
    );
</code></pre>

<events><modules><api>
Craftcms 3 Module - API call validation (on EVENT_BEFORE_SAVE, EVENT_BEFORE_VALIDATE, EVENT_AFTER_VALIDATE, EVENT_AFTER_SAVE)
# Craftcms 3 Module - API call validation (on EVENT_BEFORE_SAVE, EVENT_BEFORE_VALIDATE, EVENT_AFTER_VALIDATE, EVENT_AFTER_SAVE)

(Asked by: username_0 on 2021-06-17)

I am trying to validate entries on Save in a Module.
My specific use case requires that the Entry validation - on failure to validate will return user to form with field errors.
On successful validation I want to use that information to call an API with the field information and if all goes well I want to save - otherwise (e.g. API error) - I want to cause validation failure and show specific errors on the form.
From My understanding: the events occur in the following order:
EVENT_BEFORE_SAVE, EVENT_BEFORE_VALIDATE, EVENT_AFTER_VALIDATE, EVENT_AFTER_SAVE
I know I can do this:
    Event::on(
        Entry::class,
        Entry::EVENT_BEFORE_VALIDATE,
        function(ModelEvent $event) {
            $entry = $event->sender;
            //if send to api failure
            $entry->addError('field','api failed');
            $event->isValid=false;

        }
    );

It allows me to invalidate the save but - It does so before the regular fields are validated.
My desire here is that I can protect some bad inputs to the API using crafts validation features and then send to API and then act upon its result.
From what I have seen - EVENT_AFTER_VALIDATE always runs even if the field validation failed.
So It made sense to me that I could check $event->isValid in EVENT_AFTER_VALIDATE so my API hit would only happen on successful validate
I have discovered that EVENT_AFTER_VALIDATE is receiving an Event instead of a ModelEvent
Which means $event->isValid cannot be used to invalidate the save or check if the validation was successful. I've tried switching this around to no avail.
I seem to be able to use $entry->addError() to invalidate the save.
I'm just missing how to find out how the regular validation went..
    Event::on(
        Entry::class,
        Entry::EVENT_AFTER_VALIDATE,
        function(Event $event) {
            $entry = $event->sender;
            //if ($event->isValid) {
                //if send to api failure
                $entry->addError('field','api failed');
            //}
        }
    );

**Tags:** events, modules, api


---

## 1 answers

### Answer by username_1 on 2021-06-17. Score: 2 | Accepted answer

You can check if an element is valid by calling Entry::validate() yourself. The problem is that if you do that inside the EVENT_BEFORE_VALIDATE hook, it might cause an infinite loop (not sure if Yii2/Craft are smart enough to detect this, may be worth testing). However, it should work fine if you execute the validation in an EVENT_BEFORE_SAVE hook:
Event::on(
    Entry::class,
    Element::EVENT_BEFORE_SAVE,
    function (ModelEvent $e) {
        $entry = $e->sender;
        // bail if the entry is not valid
        if (!$entry->validate()) return;

        // now we can safely execute the API call since the entry is valid
    },
);

If the validation fails, you don't have to do anything else because the Craft will prevent saving the entry anyway. If the validation succeeds, you know the regular fields are valid and can continue with your API call. If something goes wrong there, you can set $e->isValid = false and it will prevent the entry from saving, same as in the EVENT_BEFORE_VALIDATE hook.
Now there might be some edge cases, for example if you have another hook modifying the entry to make it valid AFTER your hook has run. But I doubt that will make a difference in practical terms.


---

