Alterations to core:
Saves all extended field data in xref tables.

@param $entity
@param $flush
546413
public function saveEntity($entity, $flush = true)
    {
        $this->preSaveEntity($entity);

        $this->getEntityManager()->persist($entity);

        if ($flush) {
            $this->getEntityManager()->flush($entity);
        }

        // Get updated fields, and include changes so that we have everything.
        $fields  = $entity->getUpdatedFields();
        $changes = [];
        if (method_exists($entity, 'getChanges')) {
            $changes = $entity->getChanges();

            // remove the fields that are part of changes as they were already saved via a setter
            $fields = array_diff_key($fields, $changes);
        }

        // Get Extended Fields to separate from standard Update statement.
        $extendedFields = [];
        $fieldList      = $this->getCustomFieldList('lead');
        foreach ($fields as $alias => $value) {
            if (in_array($fieldList[0][$alias]['object'], ['extendedField', 'extendedFieldSecure'])) {
                // Depends on object added by alteration in organizeFieldsByGroup.
                $extendedFields[$alias]['object'] = $fieldList[0][$alias]['object'];
                $extendedFields[$alias]['id']     = $fieldList[0][$alias]['id'];
                $extendedFields[$alias]['type']   = $fieldList[0][$alias]['type'];
                $extendedFields[$alias]['alias']  = $alias;
                $extendedFields[$alias]['value']  = $value;
                unset($fields[$alias]);
            }
        }

        $this->prepareDbalFieldsForSave($fields);

        // Save standard/core fields (same as core).
        if (!empty($fields)) {
            $table = $this->getEntityManager()->getClassMetadata($this->getClassName())->getTableName();
            $this->getEntityManager()->getConnection()->update($table, $fields, ['id' => $entity->getId()]);
        }

        // Now to update extended fields if there were any to be updated.
        if (!empty($extendedFields)) {
            $insertUpdates = $deletions = [];
            $leadId        = $entity->getId();
            /** @var \Doctrine\DBAL\Connection $connection */
            $connection = $this->getEntityManager()->getConnection();
            foreach ($extendedFields as $extendedField) {
                if (
                    !isset($changes['fields'])
                    || !isset($changes['fields'][$extendedField['alias']])
                ) {
                    // No change to this extended field detected.
                    continue;
                }
                $schema  = $this->leadFieldModel->getSchemaDefinition($extendedField['alias'], $extendedField['type']);
                $columns = [
                    'value' => $extendedField['value'],
                ];
                // Corrects boolean field values, nothing more at this point.
                $this->prepareDbalFieldsForSave($columns);
                $secure    = 'extendedFieldSecure' === $extendedField['object'] ? '_secure' : '';
                $tableName = MAUTIC_TABLE_PREFIX.'lead_fields_leads_'.$schema['type'].$secure.'_xref';

                if (
                    null !== $changes['fields'][$extendedField['alias']][0]
                    && null === $changes['fields'][$extendedField['alias']][1]
                ) {
                    // Removed an existing value.
                    $connection->delete(
                        $tableName,
                        [
                            'lead_id'       => $leadId,
                            'lead_field_id' => $extendedField['id'],
                        ]
                    );
                } else {
                    // Mark for insert/update.
                    if (!isset($insertUpdates[$tableName])) {
                        $insertUpdates[$tableName] = [];
                    }
                    if (!isset($insertUpdates[$tableName][$extendedField['id']])) {
                        $insertUpdates[$tableName][$extendedField['id']] = $columns['value'];
                    }
                }
            }
            // Handle inserts/updates in bulk by table.
            if ($insertUpdates) {
                foreach ($insertUpdates as $tableName => $leadField) {
                    $rows = $params = [];
                    foreach ($leadField as $leadFieldId => $value) {
                        $key          = $tableName.$leadFieldId;
                        $rows[]       = $leadId.', '.$leadFieldId.', :'.$key;
                        $params[$key] = $value;
                    }
                    $sql  = 'INSERT INTO '.$tableName.' (`lead_id`, `lead_field_id`, `value`) '.
                        'VALUES ('.implode('),(', $rows).') '.
                        'ON DUPLICATE KEY UPDATE `value`=VALUES(`value`);';
                    $stmt = $connection->prepare($sql);
                    $stmt->execute($params);
                }
            }
        }

        $this->postSaveEntity($entity);
    }
611796
public function save(AbstractEntity $entity)
    {
        if (empty($entity->getId())) {
            $this->getEntityManager()->persist($entity);
        }
        $this->getEntityManager()->flush($entity);
    }
143443
public function update($entity)
    {
        $data = $this->mapper->toDbTableRow($entity);
        $this->specificationQuery->update($data->toArray());
        return true;
    }
150137
public function saveKeyValues(Entity $entity, array $keys)
    {
        $event = $this->_table->dispatchEvent('Model.beforeSaveKeyValues', compact('entity'));

        if ($event->isStopped()) {
            return $event->result;
        }

        if (!empty($event->result)) {
            $entity = $event->result;
        }

        $fields = $this->config('fields');

        if ($entity->has($fields['key']) && $entity->has($fields['value'])) {
            return true;
        }

        $mappedIds = $this->_getFieldToIdMapping($keys);

        $entities = [];
        foreach ($entity->toArray() as $key => $value) {
            if ($this->_table->hasField($key)) {
                continue;
            }

            $serialized = false;
            if (in_array($key, $this->config('serializeFields'))) {
                $value = serialize($value);
                $serialized = true;
            }

            /** @var Setting $kvEntity */
            $kvEntity = $this->_table->newEntity([
                'scope' => $this->config('scope'),
                $this->config('fields.key') => $key,
                $this->config('fields.value') => $value,
                'serialized' => $serialized
            ]);

            if (($existingId = Hash::get($mappedIds, $key)) !== null) {
                $kvEntity->id = $existingId;
            }

            $entities[] = $kvEntity;
        }

        $result = $this->_table->connection()->transactional(function () use ($entities) {
            foreach ($entities as $e) {
                $this->_table->save($e);
            }
        });

        return ($result !== false);
    }
599094
public function insert($entity)
    {
        $persistor = new CsvPersistor(
            $this->gateway,
            $this->table,
            $this->entityRegistry->getEntityBuilder(),
            $this->entityRegistry
        );
        $persistor->insert($entity);
    }
1286047
public function refresh($entity)
    {
        $fields = $this->getFields();

        foreach ($fields as $key => $mapping) {
            $fieldType = $this->fieldManager->get($mapping['fieldtype'], $mapping);
            $getter = 'get' . ucfirst($key);
            $value = $entity->$getter();
            if ($value) {
                $fieldType->set($entity, $value);
            }
        }
    }
493067
public void put(Entity entity) {
    int bytesHere = EntityTranslator.convertToPb(entity).getSerializedSize();

    // Do this before the add so that we guarantee that size is never > sizeLimit
    if (putsBytes + bytesHere >= params.getBytesLimit()) {
      flushPuts();
    }

    putsBytes += bytesHere;
    puts.add(entity);

    if (puts.size() >= params.getCountLimit()) {
      flushPuts();
    }
  }
468581
public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $options): void
    {
        if (!$entity->isNew() && $entity->dirty()) {
            $saveHash = Security::hash(md5(uniqid()));
            if (empty($entity->save_hash)) {
                $entity->save_hash = $saveHash;
                $entity->dirty('save_hash', false);
            }

            $this->_dirtyFields[$entity->id] = $this->_extractDirtyFields($entity);
            $this->_applySaveHash($entity, $saveHash);
        }
    }
1064799
protected function saveLastId($entity, $id)
    {
        $this->debugLog(sprintf('Last ID fetched: %d', $id));

        $_SESSION['behat']['GenesisSqlExtension']['last_id'][$entity][] = $id;
    }
1223725
protected function afterSave(EntityInterface $entity): void
    {
        $argv = compact('entity');
        $argv = $this->getEventManager()->prepareArgs($argv);

        $this->getEventManager()->trigger("{$this->event_prefix}_save_after", $this, $argv);
        if ($this->entity_event_prefix) {
            $this->getEventManager()->trigger("{$this->entity_event_prefix}_save_after", $this, $argv);
        }
    }
272220
protected function persist($entity)
    {
        $manager = $this->getDoctrine()->getManager();
        $manager->persist($entity);
        $manager->flush();
    }
699764
protected function save($entities)
    {
        if (!is_array($entities)) {
            $entities = [$entities];
        }

        foreach ($entities as $entity) {
            $entityClass = get_class($entity);
            $entityManager = $this
                ->get('base.object_manager_provider')
                ->getObjectManagerByEntityNamespace($entityClass);
            $entityManager->persist($entity);
            $entityManager->flush($entity);
        }
    }
194847
public function persistAndFlush($entity, $persistAll = false, $entityManager = null)
    {
        $entityManager = $this->getEntityManager($entityManager);

        $entityManager->persist($entity);
        $entityManager->flush($persistAll ? null : $entity);
    }
482274
protected function _updateField($entity, $field, $refreshTimestamp)
    {
        if ($entity->isDirty($field)) {
            return;
        }

        $ts = $this->timestamp(null, $refreshTimestamp);

        $columnType = $this->getTable()->getSchema()->getColumnType($field);
        if (!$columnType) {
            return;
        }

        /** @var \Cake\Database\Type\DateTimeType $type */
        $type = Type::build($columnType);

        if (!$type instanceof Type\DateTimeType) {
            deprecationWarning('TimestampBehavior support for column types other than DateTimeType will be removed in 4.0.');
            $entity->set($field, (string)$ts);

            return;
        }

        $class = $type->getDateTimeClassName();

        $entity->set($field, new $class($ts));
    }
791540
private function handleEntity($entity)
    {
        if (null !== $page = $this->findRelatedPage($entity)) {
            if (null === $page->getId()) {
                return;
            }
            if (!$this->pages->contains($page)) {
                $this->pages->add($page);
            }
        }
    }
275928
public function saveToEntity($entity, $formData, $limitFields = null)
    {
        foreach($formData as $field => $value) {
            $setter_name = "set".$this->dashesToCamelCase($field);

            if (($limitFields === null || in_array($field, $limitFields)) && method_exists($entity, $setter_name)) {
                $entity->$setter_name($value);
            }
        }
    }
1097412
public function save($object, $flush = true)
    {
        $this->isExpectedObject($object);
        $this->objectManager->persist($object);
        if ($flush) {
            $this->flush();
        }
    }