Body: <p>I have a module that sends an email whenever a specific entry field is updated. Everything is working fine except that the field is being passed to the dirtyFields array even if it has not been updated causing the email to be sent when not needed.</p>
  <p>Here is how the code works, I have an event (EVENT_AFTER_SAVE) being called when the entry is being saved, I check the type of the entry being saved, and if it is the correct one I do a subsequent check to see what fields changed for the entry, if the field needed has changed then it should send the email.</p>
  <p>Here is the function that the event triggers:</p>
  <pre><code>function (ModelEvent $event) {
      $entry = $event-&gt;sender;
  
      if (ElementHelper::isDraftOrRevision($entry)) {
          return;
      }
  
      if ($entry-&gt;type == 'store') {
          $dirtyFields = $entry-&gt;getDirtyFields();
  
          $this::$instance-&gt;sendEntryNotification($entry);
  
          foreach ($dirtyFields as $field) {
              if ($field == 'storeStatusV2') {
                  $this::$instance-&gt;sendEntryNotification($entry);
              }
          }
      }
  }
  </code></pre>
  <p>After doing some testing I realized that dirtyFields is returning all the fields inside the entry instead of the ones that have changed. What is the reason for this ?</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-09T21:29:19.230Z
Comments.Text: I believe any time the `setFieldValue()` method is called, it flags the field as "dirty," even if the _values_ are the same. Any form that POSTs all of an Elements fields would result in the scenario you're describing, even if the values weren't “modified” from our perspective. To my knowledge, the only way to detect an actual change would be to re-load the Element out of the database _prior_ to it being saved (in `EVENT_BEFORE_SAVE`), memoize it somewhere, then in your `EVENT_AFTER_SAVE` handler, normalize + compare the values directly.
Comments.UserDisplayName: August Miller
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-18T16:51:14.297Z
Comments.Text: mm, that is a weird implementation since the documentation explains that dirty fields are the fields that have changed since they were loaded. I wonder if there is any other way to achieve this by using the same EVENT.
Comments.UserDisplayName: Jorge Sosa
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-11-22T16:26:52.810Z
Comments.Text: Experiencing the same issue with craft 4.
Comments.UserDisplayName: Masiorama
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-11-22T16:39:12.770Z
Comments.Text: Interesting info about the issue: https://github.com/craftcms/cms/issues/12967
Comments.UserDisplayName: Masiorama
Tags: <plugin-development><php><modules>
Title: getDirtyFields returning more results than expected
ThreadText: # getDirtyFields returning more results than expected
  
  (Asked by: username_0 on 2021-11-09)
  
  I have a module that sends an email whenever a specific entry field is updated. Everything is working fine except that the field is being passed to the dirtyFields array even if it has not been updated causing the email to be sent when not needed.
  
  Here is how the code works, I have an event (EVENT\_AFTER\_SAVE) being called when the entry is being saved, I check the type of the entry being saved, and if it is the correct one I do a subsequent check to see what fields changed for the entry, if the field needed has changed then it should send the email.
  
  Here is the function that the event triggers:
  
  ```
  function (ModelEvent $event) {
      $entry = $event->sender;
  
      if (ElementHelper::isDraftOrRevision($entry)) {
          return;
      }
  
      if ($entry->type == 'store') {
          $dirtyFields = $entry->getDirtyFields();
  
          $this::$instance->sendEntryNotification($entry);
  
          foreach ($dirtyFields as $field) {
              if ($field == 'storeStatusV2') {
                  $this::$instance->sendEntryNotification($entry);
              }
          }
      }
  }
  
  ```
  
  After doing some testing I realized that dirtyFields is returning all the fields inside the entry instead of the ones that have changed. What is the reason for this ?
  
  **Tags:** plugin-development, php, modules
  
  > **Comments:**
  > **username_1**: I believe any time the `setFieldValue()` method is called, it flags the field as "dirty," even if the _values_ are the same. Any form that POSTs all of an Elements fields would result in the scenario you're describing, even if the values weren't “modified” from our perspective. To my knowledge, the only way to detect an actual change would be to re-load the Element out of the database _prior_ to it being saved (in `EVENT_BEFORE_SAVE`), memoize it somewhere, then in your `EVENT_AFTER_SAVE` handler, normalize + compare the values directly.  
  > **username_0**: mm, that is a weird implementation since the documentation explains that dirty fields are the fields that have changed since they were loaded. I wonder if there is any other way to achieve this by using the same EVENT.  
  > **username_2**: Experiencing the same issue with craft 4.  
  > **username_2**: Interesting info about the issue: https://github.com/craftcms/cms/issues/12967  
  
  ---
  
  ## 0 answers
  
  