Test if link field / relationship has changed on entity update

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • onepoint0
    Member
    • Jul 2023
    • 41

    Test if link field / relationship has changed on entity update

    Hello,

    I have a record called Camera. It has a one to one relationship on it with a lens component. I want to create some history records when the lens is changed and I have created the following code from this forum topic:

    PHP Code:
    namespace Espo\Custom\Services;
    
    use \Espo\ORM\Entity;
    
    class Camera extends \Espo\Core\Templates\Services\Base
    {
        public function loadAdditionalFields(Entity $entity)
        {
            $GLOBALS['log']->debug('in camera service: loadAdditionalFields ');
    
            parent::loadAdditionalFields($entity);
    
    // do something here to find out if camera - lens relationship has changed
            $this->loadEntryLensHistory($entity);
    
        }
    
        public function loadAdditionalFieldsForList(Entity $entity)
        {
            $GLOBALS['log']->debug('in camera service: loadAdditionalFieldsForList ');
    
        }
    
        protected function loadEntryLensHistory(Entity $entity)
        {
    
            // here I will create the history relationship between the camera and the lens
            $GLOBALS['log']->debug('this fires for any change not just for camera-lens relationship change ');
        }
    }
    But loadEntryLensHistory is being called on every update of the camera entity. I need it to only be called if the 1:1 relationship between the camera and the lens has changed. How can I identify this change? I have tried using the fetched methods and $entity->isFieldChanged - they don't seem to work and I don't think they are supposed to be used for relationships, however I can't find any other way to do it.

    Cheers,
    Clare
  • yuri
    Member
    • Mar 2014
    • 8467

    #2
    Hi Clare,

    I think $entity->isFIeldChanged('yourLinkNameId'); should work. Did you try with the 'Id' appended?

    It's better to use a field loaded https://docs.espocrm.com/development...rclassnamelist instead of extending a service class. It will be more backward compatible.
    If you find EspoCRM good, we would greatly appreciate if you could give the project a star on GitHub. We believe our work truly deserves more recognition. Thanks.

    Comment

    • onepoint0
      Member
      • Jul 2023
      • 41

      #3
      Thanks Yuri - I think I have tried this, unless I'm misunderstanding what you mean by the 'yourLinkNameId' part is. The relationship is like this:

      Click image for larger version  Name:	espo-cam-lens-rel.png Views:	0 Size:	69.0 KB ID:	98673

      Here is the layout of the detail panel on the Camera:

      Click image for larger version  Name:	camera-detail-espo.png Views:	0 Size:	38.8 KB ID:	98674

      I have altered my code to test if both $entity->isFieldChanged and $entity->isAttributeChanged can recognise a change in the relationship between the camera and the lens. I've tried it for all the possible values that could represent the relationship (from the top image Camera, camera, lens and Lens), but none of these resolve to true when I change which lens is associated with the camera. Both isFieldChanged and isAttributeChanged resolve to true for a change in the main name field. My full code is here:

      PHP Code:
      
      namespace Espo\Custom\Services;
      
      use \Espo\ORM\Entity;
      
      class Camera extends \Espo\Core\Templates\Services\Base
      {
          public function loadAdditionalFields(Entity $entity)
          {
              $GLOBALS['log']->debug('in camera service: loadAdditionalFields ');
      
              parent::loadAdditionalFields($entity);
      
              $fields = ['lens','name','camera','Camera','Lens'];
      
              foreach ($fields as $field) {
                  $GLOBALS['log']->debug('');
                  $this->fieldChanged($entity,$field);
                  $this->attChanged($entity,$field);
        
              }
          }
      
          private function fieldChanged(Entity $entity,String $field) {
      
              if ( $entity->isFieldChanged($field) ) {
                  $GLOBALS['log']->debug('Field ' . $field . ' CHANGED');
              } else {
                  $GLOBALS['log']->debug('Field ' . $field . ' NOT changed');
              }
          }
      
          private function attChanged(Entity $entity,String $field) {
      
              if ( $entity->isAttributeChanged($field) ) {
                  $GLOBALS['log']->debug('Attribute ' . $field . ' CHANGED');
              } else {
                  $GLOBALS['log']->debug('Attribute ' . $field . ' NOT changed');
              }
            
          }
      }
      

      Ultimately it's testing:

      PHP Code:
      
      $entity->isFieldChanged('name'); // true when name field is changed
      
      $entity->isFieldChanged('Camera'); // false when camera - lens relationship is changed
      
      $entity->isFieldChanged('camera'); // false when camera - lens relationship is changed
      
      $entity->isFieldChanged('lens'); // false when camera - lens relationship is changed
      ​
      $entity->isFieldChanged('Lens'); // false when camera - lens relationship is changed
      ​​ 
      
      It's the same outcome when using $entity->isAttributeChanged

      Cheers,
      Clare
      Last edited by onepoint0; 10-17-2023, 03:32 AM.

      Comment

      • onepoint0
        Member
        • Jul 2023
        • 41

        #4
        Hi Yuri, I realise now you're telling me to use lensId, eg:

        PHP Code:
        $entity->isFieldChanged('lensId');
        $entity->isAttributeChanged('lensId'); 
        

        Both work when I call them in a beforeSave or afterSave hook but not in the extended service class I've written above. I am going to try it with the readLoaderClassNameList you recommended.

        Cheers,
        Clare

        Comment

        • yuri
          Member
          • Mar 2014
          • 8467

          #5
          Right. An attribute is already marked as 'clean' after ORM's save is processed. As a workaround, you can store (in variable or in a notStorable field) the value before save, then compare with the value after save. If changed, then process loading.
          If you find EspoCRM good, we would greatly appreciate if you could give the project a star on GitHub. We believe our work truly deserves more recognition. Thanks.

          Comment

          • onepoint0
            Member
            • Jul 2023
            • 41

            #6
            Thanks a lot for all the pointers Yuri - I ended up doing it with a saverClassNameList where the entity is not yet saved, so the isAttributeChanged method still returns the value I need.

            Comment

            Working...