entityType)) { $name = get_class($this); if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { $name = $matches[1]; } if ($name != 'Record') { $this->entityType = Util::normilizeScopeName($name); } } $this->entityName = $this->entityType; } public function prepare() { parent::prepare(); $aclManager = $this->getInjection('aclManager'); foreach ($aclManager->getScopeRestrictedAttributeList($this->entityType, 'forbidden') as $item) { if (!in_array($item, $this->forbiddenAttributeList)) $this->forbiddenAttributeList[] = $item; } foreach ($aclManager->getScopeRestrictedAttributeList($this->entityType, 'internal') as $item) { if (!in_array($item, $this->internalAttributeList)) $this->internalAttributeList[] = $item; } foreach ($aclManager->getScopeRestrictedAttributeList($this->entityType, 'onlyAdmin') as $item) { if (!in_array($item, $this->onlyAdminAttributeList)) $this->onlyAdminAttributeList[] = $item; } foreach ($aclManager->getScopeRestrictedAttributeList($this->entityType, 'readOnly') as $item) { if (!in_array($item, $this->readOnlyAttributeList)) $this->readOnlyAttributeList[] = $item; } foreach ($aclManager->getScopeRestrictedAttributeList($this->entityType, 'nonAdminReadOnly') as $item) { if (!in_array($item, $this->nonAdminReadOnlyAttributeList)) $this->nonAdminReadOnlyAttributeList[] = $item; } foreach ($aclManager->getScopeRestrictedLinkList($this->entityType, 'forbidden') as $item) { if (!in_array($item, $this->forbiddenLinkList)) $this->forbiddenLinkList[] = $item; } foreach ($aclManager->getScopeRestrictedLinkList($this->entityType, 'internal') as $item) { if (!in_array($item, $this->internalLinkList)) $this->internalLinkList[] = $item; } foreach ($aclManager->getScopeRestrictedLinkList($this->entityType, 'onlyAdmin') as $item) { if (!in_array($item, $this->onlyAdminLinkList)) $this->onlyAdminLinkList[] = $item; } foreach ($aclManager->getScopeRestrictedLinkList($this->entityType, 'readOnly') as $item) { if (!in_array($item, $this->readOnlyLinkList)) $this->readOnlyLinkList[] = $item; } foreach ($aclManager->getScopeRestrictedLinkList($this->entityType, 'nonAdminReadOnly') as $item) { if (!in_array($item, $this->nonAdminReadOnlyLinkList)) $this->nonAdminReadOnlyLinkList[] = $item; } } public function setEntityType($entityType) { $this->entityType = $entityType; $this->entityName = $entityType; } public function getEntityType() { return $this->entityType; } protected function getServiceFactory() { return $this->injections['serviceFactory']; } protected function getSelectManagerFactory() { return $this->injections['selectManagerFactory']; } protected function getAcl() { if ($this->acl) return $this->acl; return $this->getInjection('acl'); } protected function getUser() { if ($this->user) return $this->user; return $this->getInjection('user'); } public function setAcl(\Espo\Core\Acl $acl) { $this->acl = $acl; } public function setUser(\Espo\Entities\User $user) { $this->user = $user; } protected function getAclManager() { return $this->getInjection('aclManager'); } protected function getFileManager() { return $this->getInjection('fileManager'); } protected function getMetadata() { return $this->getInjection('metadata'); } protected function getFieldManagerUtil() { return $this->getInjection('fieldManagerUtil'); } protected function getRepository() { return $this->getEntityManager()->getRepository($this->entityType); } protected function getRecordService($name) { if ($this->getServiceFactory()->checkExists($name)) { $service = $this->getServiceFactory()->create($name); } else { $service = $this->getServiceFactory()->create('Record'); $service->setEntityType($name); } return $service; } protected function processActionHistoryRecord($action, Entity $entity) { if ($this->actionHistoryDisabled) return; if ($this->getConfig()->get('actionHistoryDisabled')) return; $historyRecord = $this->getEntityManager()->getEntity('ActionHistoryRecord'); $historyRecord->set('action', $action); $historyRecord->set('userId', $this->getUser()->id); $historyRecord->set('authTokenId', $this->getUser()->get('authTokenId')); $historyRecord->set('ipAddress', $this->getUser()->get('ipAddress')); $historyRecord->set('authLogRecordId', $this->getUser()->get('authLogRecordId')); if ($entity) { $historyRecord->set([ 'targetType' => $entity->getEntityType(), 'targetId' => $entity->id ]); } $this->getEntityManager()->saveEntity($historyRecord); } public function readEntity($id) //TODO Remove in 5.8 { return $this->read($id); } public function read($id) { if (empty($id)) { throw new Error(); } $entity = $this->getEntity($id); if (!$entity) throw new NotFoundSilent("Record does not exist."); $this->processActionHistoryRecord('read', $entity); return $entity; } public function getEntity($id = null) { if (!is_null($id)) { $selectParams = []; if ($this->getUser()->isAdmin()) { $selectParams['withDeleted'] = true; } $entity = $this->getRepository()->getById($id, $selectParams); } else { $entity = $this->getRepository()->getNew(); } if ($entity && !is_null($id)) { $this->loadAdditionalFields($entity); if (!$this->getAcl()->check($entity, 'read')) throw new ForbiddenSilent(); $this->prepareEntityForOutput($entity); } return $entity; } protected function getStreamService() { if (empty($this->streamService)) { $this->streamService = $this->getServiceFactory()->create('Stream'); } return $this->streamService; } protected function loadIsFollowed(Entity $entity) { if ($this->getStreamService()->checkIsFollowed($entity)) { $entity->set('isFollowed', true); } else { $entity->set('isFollowed', false); } } protected function loadFollowers(Entity $entity) { if ($this->getUser()->isPortal()) return; if (!$this->getMetadata()->get(['scopes', $entity->getEntityType(), 'stream'])) return; if (!$this->getAcl()->check($entity, 'stream')) return; $data = $this->getStreamService()->getEntityFollowers($entity, 0, self::FOLLOWERS_LIMIT); if ($data) { $entity->set('followersIds', $data['idList']); $entity->set('followersNames', $data['nameMap']); } } protected function loadLinkMultipleFields(Entity $entity) { $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.fields', array()); foreach ($fieldDefs as $field => $defs) { if (isset($defs['type']) && in_array($defs['type'], ['linkMultiple', 'attachmentMultiple']) && empty($defs['noLoad'])) { $columns = null; if (!empty($defs['columns'])) { $columns = $defs['columns']; } $entity->loadLinkMultipleField($field, $columns); } } } public function loadLinkMultipleFieldsForList(Entity $entity, $selectAttributeList) { foreach ($selectAttributeList as $attribute) { if ($entity->getAttributeParam($attribute, 'isLinkMultipleIdList')) { $field = $entity->getAttributeParam($attribute, 'relation'); if (!$field) continue; if ($entity->has($attribute)) continue; $entity->loadLinkMultipleField($field); } } } protected function loadLinkFields(Entity $entity) { $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.fields', array()); $linkDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.links', array()); foreach ($fieldDefs as $field => $defs) { if (isset($defs['type']) && $defs['type'] === 'link') { if (!empty($defs['noLoad'])) continue; if (empty($linkDefs[$field])) continue; if (empty($linkDefs[$field]['type'])) continue; if ($linkDefs[$field]['type'] !== 'hasOne') continue; $entity->loadLinkField($field); } } } protected function loadParentNameFields(Entity $entity) { $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.fields', array()); foreach ($fieldDefs as $field => $defs) { if (isset($defs['type']) && $defs['type'] == 'linkParent') { $parentId = $entity->get($field . 'Id'); $parentType = $entity->get($field . 'Type'); $entity->loadParentNameField($field); } } } protected function loadNotJoinedLinkFields(Entity $entity) { $linkDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.links', array()); foreach ($linkDefs as $link => $defs) { if (isset($defs['type']) && $defs['type'] == 'belongsTo') { if (!empty($defs['noJoin']) && !empty($defs['entity'])) { $nameAttribute = $link . 'Name'; $idAttribute = $link . 'Id'; if ($entity->hasAttribute($nameAttribute) && $entity->hasAttribute($idAttribute)) { $id = $entity->get($idAttribute); } else { continue; } if (!empty($defs['entity'])) { $scope = $defs['entity']; if ($this->getEntityManager()->hasRepository($scope)) { $foreignEntity = $this->getEntityManager()->getRepository($scope) ->select(['id', 'name']) ->where(['id' => $id]) ->findOne(); if ($foreignEntity) { $entity->set($nameAttribute, $foreignEntity->get('name')); } else { $entity->set($nameAttribute, null); } } } } } } } protected function loadEmptyNameLinkFields(Entity $entity) { $linkDefs = $this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'links'], []); foreach ($linkDefs as $link => $defs) { if (!isset($defs['type'])) continue; if ($defs['type'] != 'belongsTo') continue; $nameAttribute = $link . 'Name'; $idAttribute = $link . 'Id'; if ($entity->get($idAttribute) && !$entity->get($nameAttribute)) { $id = $entity->get($idAttribute); if (empty($defs['entity'])) continue; $scope = $defs['entity']; if ($this->getEntityManager()->hasRepository($scope)) { $foreignEntity = $this->getEntityManager()->getRepository($scope) ->select(['id', 'name']) ->where(['id' => $id]) ->findOne(); if ($foreignEntity) { $entity->set($nameAttribute, $foreignEntity->get('name')); } } } } } public function loadAdditionalFields(Entity $entity) { $this->loadLinkFields($entity); $this->loadLinkMultipleFields($entity); $this->loadParentNameFields($entity); $this->loadIsFollowed($entity); $this->loadFollowers($entity); $this->loadEmailAddressField($entity); $this->loadPhoneNumberField($entity); $this->loadNotJoinedLinkFields($entity); $this->loadEmptyNameLinkFields($entity); } public function loadAdditionalFieldsForList(Entity $entity) { $this->loadParentNameFields($entity); } public function loadAdditionalFieldsForExport(Entity $entity) { } protected function loadEmailAddressField(Entity $entity) { $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.fields', array()); if (!empty($fieldDefs['emailAddress']) && $fieldDefs['emailAddress']['type'] == 'email') { $dataAttributeName = 'emailAddressData'; $emailAddressData = $this->getEntityManager()->getRepository('EmailAddress')->getEmailAddressData($entity); $entity->set($dataAttributeName, $emailAddressData); $entity->setFetched($dataAttributeName, $emailAddressData); } } protected function loadPhoneNumberField(Entity $entity) { $fieldDefs = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() . '.fields', array()); if (!empty($fieldDefs['phoneNumber']) && $fieldDefs['phoneNumber']['type'] == 'phone') { $dataAttributeName = 'phoneNumberData'; $phoneNumberData = $this->getEntityManager()->getRepository('PhoneNumber')->getPhoneNumberData($entity); $entity->set($dataAttributeName, $phoneNumberData); $entity->setFetched($dataAttributeName, $phoneNumberData); } } protected function getSelectManager($entityType = null) { if (!$entityType) { $entityType = $this->getEntityType(); } return $this->getSelectManagerFactory()->create($entityType); } protected function storeEntity(Entity $entity) { return $this->getRepository()->save($entity); } public function processValidation(Entity $entity, $data) { $fieldList = $this->getFieldManagerUtil()->getEntityTypeFieldList($this->entityType); foreach ($fieldList as $field) { if (in_array($field, $this->validateSkipFieldList)) continue; if (!$entity->isNew()) { if (!$this->isFieldSetInData($data, $field)) continue; } $this->processValidationField($entity, $field, $data); } } protected function processValidationField(Entity $entity, $field, $data) { $fieldType = $this->getFieldManagerUtil()->getEntityTypeFieldParam($this->entityType, $field, 'type'); $validationList = $this->getMetadata()->get(['fields', $fieldType, 'validationList'], []); $mandatoryValidationList = $this->getMetadata()->get(['fields', $fieldType, 'mandatoryValidationList'], []); $fieldValidatorManager = $this->getInjection('container')->get('fieldValidatorManager'); foreach ($validationList as $type) { $value = $this->getFieldManagerUtil()->getEntityTypeFieldParam($this->entityType, $field, $type); if (is_null($value)) { if (!in_array($type, $mandatoryValidationList)) { continue; } } $skipPropertyName = 'validate' . ucfirst($type) . 'SkipFieldList'; if (property_exists($this, $skipPropertyName)) { $skipList = $this->$skipPropertyName; if (in_array($type, $skipList)) { continue; } } if (!$fieldValidatorManager->check($entity, $field, $type, $data)) { throw new BadRequest("Not valid data. Field: '{$field}', type: {$type}."); } } } protected function isFieldSetInData($data, $field) { $attributeList = $this->getFieldManagerUtil()->getActualAttributeList($this->entityType, $field); $isSet = false; foreach ($attributeList as $attribute) { if (property_exists($data, $attribute)) { $isSet = true; break; } } return $isSet; } public function checkAssignment(Entity $entity) { if (!$this->isPermittedAssignedUser($entity)) { return false; } if (!$this->isPermittedTeams($entity)) { return false; } if ($entity->hasLinkMultipleField('assignedUsers')) { if (!$this->isPermittedAssignedUsers($entity)) { return false; } } return true; } public function isPermittedAssignedUsers(Entity $entity) { if (!$entity->hasLinkMultipleField('assignedUsers')) { return true; } if ($this->getUser()->isPortal()) { if (count($entity->getLinkMultipleIdList('assignedUsers')) === 0) { return true; } } $assignmentPermission = $this->getAcl()->get('assignmentPermission'); if ($assignmentPermission === true || $assignmentPermission === 'yes' || !in_array($assignmentPermission, ['team', 'no'])) { return true; } $toProcess = false; if (!$entity->isNew()) { $userIdList = $entity->getLinkMultipleIdList('assignedUsers'); if ($entity->isAttributeChanged('assignedUsersIds')) { $toProcess = true; } } else { $toProcess = true; } $userIdList = $entity->getLinkMultipleIdList('assignedUsers'); if ($toProcess) { if (empty($userIdList)) { if ($assignmentPermission == 'no') { return false; } return true; } $fetchedAssignedUserIdList = $entity->getFetched('assignedUsersIds'); if ($assignmentPermission == 'no') { foreach ($userIdList as $userId) { if (!$entity->isNew() && in_array($userId, $fetchedAssignedUserIdList)) continue; if ($this->getUser()->id != $userId) { return false; } } } else if ($assignmentPermission == 'team') { $teamIdList = $this->getUser()->getLinkMultipleIdList('teams'); foreach ($userIdList as $userId) { if (!$entity->isNew() && in_array($userId, $fetchedAssignedUserIdList)) continue; if (!$this->getEntityManager()->getRepository('User')->checkBelongsToAnyOfTeams($userId, $teamIdList)) { return false; } } } } return true; } public function isPermittedAssignedUser(Entity $entity) { if (!$entity->hasAttribute('assignedUserId')) { return true; } $assignedUserId = $entity->get('assignedUserId'); if ($this->getUser()->isPortal()) { if (!$entity->isAttributeChanged('assignedUserId') && empty($assignedUserId)) { return true; } } $assignmentPermission = $this->getAcl()->get('assignmentPermission'); if ($assignmentPermission === true || $assignmentPermission === 'yes' || !in_array($assignmentPermission, ['team', 'no'])) { return true; } $toProcess = false; if (!$entity->isNew()) { if ($entity->isAttributeChanged('assignedUserId')) { $toProcess = true; } } else { $toProcess = true; } if ($toProcess) { if (empty($assignedUserId)) { if ($assignmentPermission == 'no') { return false; } return true; } if ($assignmentPermission == 'no') { if ($this->getUser()->id != $assignedUserId) { return false; } } else if ($assignmentPermission == 'team') { $teamIdList = $this->getUser()->get('teamsIds'); if (!$this->getEntityManager()->getRepository('User')->checkBelongsToAnyOfTeams($assignedUserId, $teamIdList)) { return false; } } } return true; } public function isPermittedTeams(Entity $entity) { $assignmentPermission = $this->getAcl()->get('assignmentPermission'); if (empty($assignmentPermission) || $assignmentPermission === true || !in_array($assignmentPermission, ['team', 'no'])) { return true; } if (!$entity->hasLinkMultipleField('teams')) { return true; } $teamIdList = $entity->getLinkMultipleIdList('teams'); if (empty($teamIdList)) { if ($assignmentPermission === 'team') { if ($entity->hasLinkMultipleField('assignedUsers')) { $assignedUserIdList = $entity->getLinkMultipleIdList('assignedUsers'); if (empty($assignedUserIdList)) { return false; } } else if ($entity->hasAttribute('assignedUserId')) { if (!$entity->get('assignedUserId')) { return false; } } } return true; } $newIdList = []; if (!$entity->isNew()) { $existingIdList = []; foreach ($entity->get('teams') as $team) { $existingIdList[] = $team->id; } foreach ($teamIdList as $id) { if (!in_array($id, $existingIdList)) { $newIdList[] = $id; } } } else { $newIdList = $teamIdList; } if (empty($newIdList)) { return true; } $userTeamIdList = $this->getUser()->getLinkMultipleIdList('teams'); foreach ($newIdList as $id) { if (!in_array($id, $userTeamIdList)) { return false; } } return true; } protected function stripTags($string) { return strip_tags($string, '