Announcement

Collapse
No announcement yet.

Possible Bug in Espo\Core\FieldProcessing\NextNumber\BeforeSaveProcessor::process()

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

  • Possible Bug in Espo\Core\FieldProcessing\NextNumber\BeforeSaveProcessor::process()

    I am encountering the following error when trying to save a Custom Entity:

    Code:
    Espo\Core\FieldProcessing\NextNumber\BeforeSaveProcessor::process():
    Argument #1 ($entity) must be of type Espo\Core\ORM\Entity,
    Espo\Modules\Natera\Entities\NateraJob given,
    called in /App/application/Espo/Hooks/Common/NextNumber.php on line 51


    EspoCRM Version: 8.1.1
    PHP Version: PHP 8.2.7 (cli) (built: Jun 9 2023 19:37:27) (NTS)

    STEPS TO REPRODUCE

    My Custom Entity inside a custom Module is Defined as follows.

    File: custom/Espo/Modules/Natera/Resources/metadata/entityDefs/NateraJob.json
    PHP Code:
    {
        
    "fields": {
            
    "jobId": {
                
    "label""Natera Job ID",
                
    "type""varchar",
                
    "length"12,
                
    "required"true,
                
    "readOnlyAfterCreate"true
            
    },
            
    "assignmentId": {
                
    "label""Assignment",
                
    "type""varchar",
                
    "length"17,
                
    "required"false
            
    },
            
    "technicianId": {
                
    "label""Natera Technician ID",
                
    "type""varchar",
                
    "length"12,
                
    "required"true
            
    },
            
    "status": {
                
    "label""Job Status",
                
    "type""enum",
                
    "required"true,
                
    "default""available",
                
    "options": [
                    
    "available",
                    
    "published",
                    
    "assigned",
                    
    "scheduled",
                    
    "on_the_way",
                    
    "on_site",
                    
    "in_progress",
                    
    "completed",
                    
    "cancelled",
                    
    "error"
                
    ]
            },
            
    "mpxData": {
                
    "type""text",
                
    "required"true,
                
    "isEncrypted"true
            
    },
            
    "mpxLog": {
                
    "type""text",
                
    "required"true
            
    },
            
    "createdAt": {
                
    "type""datetime",
                
    "readOnly"true
            
    },
            
    "modifiedAt": {
                
    "type""datetime",
                
    "readOnly"true
            
    },
            
    "address": {
                
    "type""address",
                
    "notStorable"true,
                
    "utility"true
            
    }
        },
        
    "indexes": {
            
    "natera_id": {
                
    "columns": ["jobId"],
                
    "unique"true
            
    },
            
    "entity_id": {
                
    "columns": ["assignmentId"]
            },
            
    "by_status": {
                
    "columns": [
                    
    "status",
                    
    "createdAt"
                
    ]
            }
        },
        
    "collection": {
            
    "orderBy""createdAt",
            
    "order""asc",
            
    "textFilterFields": [
                
    "status"
            
    ]
        }

    File: custom/Espo/Modules/Natera/Entities/NateraJob.php
    PHP Code:
    namespace Espo\Modules\Natera\Entities;

    use 
    Espo\ORM\BaseEntity;
    use 
    Espo\ORM\EntityManager;
    use 
    Espo\ORM\Value\ValueAccessorFactory;
    use 
    Espo\Core\Utils\Crypt;

    class 
    NateraJob extends BaseEntity
    {
        private 
    $isEncrypted;

        public function 
    __construct(
            
    string $entityType,
            array 
    $defs,
            ?
    EntityManager $entityManager null,
            ?
    ValueAccessorFactory $valueAccessorFactory null,
            private 
    Crypt $crypt,
        ) {
            
    parent::__construct(
                
    $entityType,
                
    $defs,
                
    $entityManager,
                
    $valueAccessorFactory
            
    );

            
    $this->isEncrypted = [];
            foreach (
    $defs['fields'] as $field => $value) {
                if (
    array_key_exists('isEncrypted'$value) && $value['isEncrypted']) {
                    
    $this->isEncrypted[] = $field;
                }
            }
        }

        protected function 
    setInContainer(string $attribute$value): void
        
    {
            if (
    in_array($attribute$this->isEncrypted)) {
                
    $value $this->crypt->encrypt($value);
            }

            
    parent::setInContainer($attribute$value);

            return;
        }

        public function 
    setFetched(string $attribute$value): void
        
    {
            if (
    in_array($attribute$this->isEncrypted)) {
                
    $value $this->crypt->decrypt($value);
                
    parent::setInContainer($attribute$value);
            }

            
    parent::setFetched($attribute$value);
        }

        protected function 
    getFromContainer(string $attribute)
        {
            
    $value parent::getFromContainer($attribute);

            if (
    in_array($attribute$this->isEncrypted)) {
                return 
    $this->crypt->decrypt($value);
            }

            return 
    $value;
        }

        public function 
    getFetched(string $attribute)
        {
            
    $value parent::getFetched($attribute);

            if (
    in_array($attribute$this->isEncrypted) && !is_null($value)) {
                
    $value $this->crypt->decrypt($value);
            }

            return 
    $value;
        }

    When I try to update an Entity I get the above error.
    For testing to recreate the error, I created code as follows inside a CLI job:

    PHP Code:
    try {

        
    $em $this->container->get('entityManager');

        
    $entity $em->getEntityById('NateraJob''65e26caac9c5d60f9');
        
    print_r($entity->getValueMap());
        
    $entity->set('assignmentId''65a0d16b7f222e498');
        
    $em->saveEntity($entity, ['SKIP_NATERA' => true]);

    } catch (
    \Throwable $error) {

        echo 
    $error->getMessage();
        echo 
    "\n";
        echo 
    $error->getTraceAsString();


    Output from code:
    Code:
    stdClass Object
    (
        [id] => 65e26caac9c5d60f9
        [deleted] =>
        [jobId] => h9c74fg2
        [assignmentId] =>
        [technicianId] => wosv2mwl
        [status] => scheduled
        [mpxData] => {"id":"h9c74fg2",/** removed private data **/}
        [mpxLog] => [{"at":"2024-01-12 19:33:19","type":"EVENT","message":"Complete Job Data Updated"},{"at":"2024-01-17 17:55:25","type":"EVENT","message":"Job Status changed to ASSIGNED"},{"at":"2024-01-17 17:55:25","type":"EVENT","message":"Job assignee changed"},{"at":"2024-01-17 17:55:25","type":"EVENT","message":"Complete Job Data Updated"},{"at":"2024-01-31 15:58:42","type":"EVENT","message":"Job Status changed to SCHEDULED"},{"at":"2024-01-31 15:58:42","type":"EVENT","message":"Job startTime changed"},{"at":"2024-03-02 00:02:50","type":"EVENT","message":"Job Migrated"}]
        [createdAt] => 2024-03-02 00:02:50
        [modifiedAt] => 2024-03-02 00:02:50
    )
    Espo\Core\FieldProcessing\NextNumber\BeforeSaveProcessor::process(): Argument #1 ($entity) must be of type Espo\Core\ORM\Entity, Espo\Modules\Natera\Entities\NateraJob given, called in /App/application/Espo/Hooks/Common/NextNumber.php on line 51
    #0 /App/application/Espo/Hooks/Common/NextNumber.php(51): Espo\Core\FieldProcessing\NextNumber\BeforeSaveProcessor->process()
    #1 /App/application/Espo/Core/Hook/GeneralInvoker.php(186): Espo\Hooks\Common\NextNumber->beforeSave()
    #2 /App/application/Espo/Core/HookManager.php(118): Espo\Core\Hook\GeneralInvoker->invoke()
    #3 /App/application/Espo/Core/Repositories/Database.php(298): Espo\Core\HookManager->process()
    #4 /App/application/Espo/ORM/Repository/RDBRepository.php(139): Espo\Core\Repositories\Database->beforeSave()
    #5 /App/application/Espo/Core/Repositories/Database.php(136): Espo\ORM\Repository\RDBRepository->save()
    #6 /App/application/Espo/ORM/EntityManager.php(244): Espo\Core\Repositories\Database->save()
    #7 /App/custom/Espo/Modules/Natera/Services/Utils/Tasks/Task/Test.php(25): Espo\ORM\EntityManager->saveEntity()
    #8 /App/custom/Espo/Modules/Natera/Services/Utils/Tasks/TaskManager.php(49): Espo\Modules\Natera\Services\Utils\Tasks\Task\Test->execute()
    #9 /App/application/Espo/Core/Job/JobRunner.php(233): Espo\Modules\Natera\Services\Utils\Tasks\TaskManager->run()
    #10 /App/application/Espo/Core/Job/JobRunner.php(194): Espo\Core\Job\JobRunner->runJob()
    #11 /App/application/Espo/Core/Job/JobRunner.php(123): Espo\Core\Job\JobRunner->runJobNamed()
    #12 /App/application/Espo/Core/Job/JobRunner.php(77): Espo\Core\Job\JobRunner->runInternal()
    #13 /App/application/Espo/Core/Job/JobManager.php(145): Espo\Core\Job\JobRunner->runThrowingException()
    #14 /App/application/Espo/Core/Console/Commands/RunJob.php(92): Espo\Core\Job\JobManager->runJob()
    #15 /App/application/Espo/Core/Console/CommandManager.php(95): Espo\Core\Console\Commands\RunJob->run()
    #16 /App/application/Espo/Core/ApplicationRunners/Command.php(51): Espo\Core\Console\CommandManager->run()
    #17 /App/application/Espo/Core/Application/RunnerRunner.php(84): Espo\Core\ApplicationRunners\Command->run()
    #18 /App/application/Espo/Core/Application.php(78): Espo\Core\Application\RunnerRunner->run()
    #19 /App/command.php(35): Espo\Core\Application->run()
    #20 /App/bin/command(4): include('...')
    #21 {main}
    Last edited by aldisa; 05-04-2024, 02:19 PM.

  • #2
    I took a look at this Class: \Espo\Core\FieldProcessing\NextNumber\BeforeSavePr ocessor

    It has the following relevant portions.

    PHP Code:
    namespace Espo\Core\FieldProcessing\NextNumber;

    use 
    Espo\Core\ORM\Entity;

        
    /**
         * @param array<string, mixed> $options
         */
        
    public function process(Entity $entity, array $options): void
        
    {
            
    $fieldList $this->getFieldList($entity->getEntityType());

            foreach (
    $fieldList as $field) {
                
    $this->processItem($entity$field$options);
            }
        } 
    If the Entity type hint for the process() function was = \Espo\ORM\Entity, then the above error would not occur.

    My custom entity (NateraJob) extends \Espo\ORM\BaseEntity which implements \Espo\ORM\Entity.
    \Espo\Core\ORM\Entity extend \Espo\ORM\BaseEntity which implements \Espo\ORM\Entity.

    Would the \Espo\Core\FieldProcessing\NextNumber\BeforeSavePr ocessor->process() function still work if the Entity implements \Espo\ORM\Entity?

    Unfortunately, I am not able to implement upgrade version of EspoCRM for my client, but I could manually make this change if appropriate.

    Look forward to your guidance in this regard.
    Last edited by aldisa; 05-03-2024, 10:50 PM.

    Comment


    • #3
      Hi,

      Consider extending from Espo\Core\ORM\Entity instead.

      Comment

      Working...
      X