Announcement

Collapse
No announcement yet.

Test if link field / relationship has changed on entity update

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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

  • #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.

    Comment


    • #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


      • #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


        • #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.

          Comment


          • #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...
            X