getEntityType(); if (!$this->acl->check($entityType, Table::ACTION_EDIT)) { throw new Forbidden("No edit access for '{$entityType}'."); } if ($this->acl->getPermissionLevel(self::PERMISSION) !== Table::LEVEL_YES) { throw new Forbidden("No mass-update permission."); } $service = $this->serviceFactory->create($entityType); $filteredData = $this->filterData($data, $service); if ($filteredData->getAttributeList() === []) { return new Result(0, []); } $copyFieldList = $this->detectFieldToCopyList($entityType, $filteredData); $query = $this->queryBuilder->build($params); $collection = $this->entityManager ->getRDBRepository($entityType) ->clone($query) ->sth() ->find(); $ids = []; $count = 0; foreach ($collection as $i => $entity) { $itemResult = $this->processEntity($entity, $filteredData, $i, $copyFieldList, $service); if (!$itemResult) { continue; } $ids[] = $entity->getId(); $count++; } return new Result($count, $ids); } /** * @param Service $service */ private function filterData(Data $data, Service $service): Data { $filteredData = $data; $values = $data->getValues(); $service->filterUpdateInput($values); foreach ($data->getAttributeList() as $attribute) { if (!property_exists($values, $attribute)) { $filteredData = $filteredData->without($attribute); continue; } $action = $filteredData->getAction($attribute) ?? Action::UPDATE; $value = $values->$attribute; $filteredData = $filteredData->with($attribute, $value, $action); } return $filteredData; } /** * @param string[] $fieldToCopyList * @param Service $service */ private function processEntity(Entity $entity, Data $data, int $i, array $fieldToCopyList, Service $service): bool { if (!$this->acl->check($entity, Table::ACTION_EDIT)) { return false; } $values = $this->prepareItemValueMap($entity, $data, $i, $fieldToCopyList); // Needed for link check. $this->linkMultipleLoader->process( $entity, LoaderParams::create() ->withSelect($data->getAttributeList()) ); $entity->set($values); try { $service->processValidation($entity, $values); } catch (Exception) { return false; } if (!$service->checkAssignment($entity)) { return false; } try { $this->linkCheck->processFields($entity); } catch (Forbidden) { return false; } $this->entityManager->saveEntity($entity, [ 'massUpdate' => true, 'skipStreamNotesAcl' => true, 'modifiedById' => $this->user->getId(), ]); $service->processActionHistoryRecord(RecordAction::UPDATE, $entity); return true; } /** * @param string[] $copyFieldList */ private function prepareItemValueMap(Entity $entity, Data $data, int $i, array $copyFieldList): stdClass { $dataModified = $this->copy($entity->getEntityType(), $data, $i, $copyFieldList); return $this->valueMapPreparator->prepare($entity, $dataModified); } /** * @param string[] $copyFieldList */ private function copy(string $entityType, Data $data, int $i, array $copyFieldList): Data { if (!count($copyFieldList)) { return $data; } if ($i === 0) { return $data; } foreach ($copyFieldList as $field) { $type = $this->fieldUtil->getEntityTypeFieldParam($entityType, $field, 'type'); if ($type === 'file' || $type === 'image') { $data = $this->copyFileField($field, $data); continue; } if ($type === 'attachmentMultiple') { $data = $this->copyAttachmentMultipleField($field, $data); continue; } } return $data; } private function copyFileField(string $field, Data $data): Data { $attribute = $field . 'Id'; $id = $data->getValue($attribute); if (!$id) { return $data; } $attachment = $this->entityManager->getEntityById(Attachment::ENTITY_TYPE, $id); if (!$attachment) { return $data->with($attribute, null); } /** @var AttachmentRepository $attachmentRepository */ $attachmentRepository = $this->entityManager->getRepository(Attachment::ENTITY_TYPE); $copiedAttachment = $attachmentRepository->getCopiedAttachment($attachment); return $data->with($attribute, $copiedAttachment->getId()); } private function copyAttachmentMultipleField(string $field, Data $data): Data { $attribute = $field . 'Ids'; $ids = $data->getValue($attribute) ?? []; if (!is_array($ids)) { throw new RuntimeException("Bad link-multiple-ids value."); } if (!count($ids)) { return $data; } /** @var AttachmentRepository $attachmentRepository */ $attachmentRepository = $this->entityManager->getRepository(Attachment::ENTITY_TYPE); $copiedIds = []; foreach ($ids as $id) { $attachment = $this->entityManager->getEntityById(Attachment::ENTITY_TYPE, $id); if (!$attachment) { continue; } $copiedIds[] = $attachmentRepository ->getCopiedAttachment($attachment) ->getId(); } return $data->with($attribute, $copiedIds); } /** * @return string[] */ private function detectFieldToCopyList(string $entityType, Data $data): array { $resultFieldList = []; $fieldList = array_merge( $this->fieldUtil->getFieldByTypeList($entityType, 'file'), $this->fieldUtil->getFieldByTypeList($entityType, 'image'), $this->fieldUtil->getFieldByTypeList($entityType, 'attachmentMultiple') ); foreach ($fieldList as $field) { $actualAttributeList = $this->fieldUtil->getActualAttributeList($entityType, $field); $met = false; foreach ($actualAttributeList as $attribute) { if ($data->getValue($attribute)) { $met = true; } } if ($met) { $resultFieldList[] = $field; } } return $resultFieldList; } }