/** * {@inheritdoc} */ public function getEntityAlias($entityClass) { if ($this->configManager->hasConfig($entityClass)) { // check for enums $enumCode = $this->configManager->getProvider('enum')->getConfig($entityClass)->get('code'); if ($enumCode) { $entityAlias = $this->getEntityAliasFromConfig($entityClass); if (null !== $entityAlias) { return $entityAlias; } return $this->createEntityAlias(str_replace('_', '', $enumCode)); } // check for dictionaries $groups = $this->configManager->getProvider('grouping')->getConfig($entityClass)->get('groups'); if (!empty($groups) && in_array(GroupingScope::GROUP_DICTIONARY, $groups, true)) { // delegate aliases generation to default provider return null; } // exclude hidden entities if ($this->configManager->isHiddenModel($entityClass)) { return false; } // check for custom entities if (ExtendHelper::isCustomEntity($entityClass)) { $entityAlias = $this->getEntityAliasFromConfig($entityClass); if (null !== $entityAlias) { return $entityAlias; } return $this->createEntityAlias('Extend' . ExtendHelper::getShortClassName($entityClass)); } } return null; }
/** * @param string $entityClassName * @param string $relationType * * @return array */ protected function getEntityChoiceList($entityClassName, $relationType) { /** @var EntityConfigId[] $entityIds */ $entityIds = $this->targetEntityClass ? [$this->configManager->getId('extend', $this->targetEntityClass)] : $this->configManager->getIds('extend'); if (in_array($relationType, [RelationTypeBase::ONE_TO_MANY, RelationTypeBase::MANY_TO_MANY], true)) { $entityIds = array_filter($entityIds, function (EntityConfigId $configId) { $config = $this->configManager->getConfig($configId); return $config->is('is_extend'); }); } $entityIds = array_filter($entityIds, function (EntityConfigId $configId) { $config = $this->configManager->getConfig($configId); return !$config->is('state', ExtendScope::STATE_NEW) && ($this->targetEntityClass || !$config->is('is_deleted')); }); $choices = []; foreach ($entityIds as $entityId) { $className = $entityId->getClassName(); if (!$this->configManager->hasConfig($className, 'id') && !ExtendHelper::isCustomEntity($className)) { // @todo: temporary ignore entities that don't have PK with name 'id' // remove this in https://magecore.atlassian.net/browse/BAP-9713 continue; } if ($className !== $entityClassName) { $entityConfig = $this->configManager->getProvider('entity')->getConfig($className); $choices[$className] = $entityConfig->get('label'); } } return $choices; }
/** * @param string $entityClass * * @return string|null */ public function getContextGridByEntity($entityClass) { if (!empty($entityClass)) { $entityClass = $this->routingHelper->resolveEntityClass($entityClass); if (ExtendHelper::isCustomEntity($entityClass)) { return 'custom-entity-grid'; } $config = $this->entityConfigProvider->getConfig($entityClass); if ($config->has('context')) { return $config->get('context'); } if ($config->has('default')) { return $config->get('default'); } } return null; }
/** * Returns the context for the given activity class and id * * @param string $class The FQCN of the activity entity * @param $id * * @return array */ public function getActivityContext($class, $id) { $criteria = Criteria::create(); $criteria->andWhere(Criteria::expr()->eq('id', $id)); $currentUser = $this->securityTokenStorage->getToken()->getUser(); $userClass = ClassUtils::getClass($currentUser); $queryBuilder = $this->activityManager->getActivityTargetsQueryBuilder($class, $criteria, null, null, null, null, function (QueryBuilder $qb, $targetEntityClass) use($currentUser, $userClass) { if ($targetEntityClass === $userClass) { // Exclude current user from result $qb->andWhere($qb->expr()->neq(QueryUtils::getSelectExprByAlias($qb, 'entityId'), $currentUser->getId())); } }); if (null === $queryBuilder) { return []; } $result = $queryBuilder->getQuery()->getResult(); if (empty($result)) { return $result; } $entityProvider = $this->configManager->getProvider('entity'); foreach ($result as &$item) { $config = $entityProvider->getConfig($item['entity']); $metadata = $this->configManager->getEntityMetadata($item['entity']); $safeClassName = $this->entityClassNameHelper->getUrlSafeClassName($item['entity']); $link = null; if ($metadata) { $link = $this->router->generate($metadata->getRoute(), ['id' => $item['id']]); } elseif ($link === null && ExtendHelper::isCustomEntity($item['entity'])) { // Generate view link for the custom entity $link = $this->router->generate('oro_entity_view', ['id' => $item['id'], 'entityName' => $safeClassName]); } $item['activityClassAlias'] = $this->entityAliasResolver->getPluralAlias($class); $item['entityId'] = $id; $item['targetId'] = $item['id']; $item['targetClassName'] = $safeClassName; $item['icon'] = $config->get('icon'); $item['link'] = $link; unset($item['id'], $item['entity']); } return $result; }
/** * @param LoggerInterface $logger * @param bool $dryRun * * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function doExecute(LoggerInterface $logger, $dryRun = false) { $configs = $this->loadConfigs($logger); foreach ($configs as $id => $item) { $data = $item['data']; if (!isset($data['extend']['is_extend']) || !$data['extend']['is_extend']) { continue; } if (empty($data['extend']['extend_class']) || empty($data['extend']['schema']['parent'])) { continue; } $className = $item['class_name']; if (ExtendHelper::isCustomEntity($className)) { continue; } $parentClass = $data['extend']['schema']['parent']; $oldExtendClass = $data['extend']['extend_class']; $newExtendClass = ExtendHelper::getExtendEntityProxyClassName($parentClass); if (!$newExtendClass || $newExtendClass === $oldExtendClass) { continue; } $data['extend']['extend_class'] = $newExtendClass; if (isset($data['extend']['schema']['entity'])) { $data['extend']['schema']['entity'] = $newExtendClass; } if (isset($data['extend']['schema']['doctrine'][$oldExtendClass])) { $data['extend']['schema']['doctrine'][$newExtendClass] = $data['extend']['schema']['doctrine'][$oldExtendClass]; unset($data['extend']['schema']['doctrine'][$oldExtendClass]); } $query = 'UPDATE oro_entity_config SET data = :data WHERE id = :id'; $params = ['data' => $data, 'id' => $id]; $types = ['data' => 'array', 'id' => 'integer']; $logger->notice(sprintf('Change extend class from "%s" to "%s" for "%s".', $oldExtendClass, $newExtendClass, $className)); $this->logQuery($logger, $query, $params, $types); if (!$dryRun) { $this->connection->executeUpdate($query, $params, $types); } } }
/** * {@inheritdoc} */ protected function hasEntityConfigs(ClassMetadata $metadata) { return parent::hasEntityConfigs($metadata) && !ExtendHelper::isCustomEntity($metadata->getName()); }
/** * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * * @param ConfigInterface $extendConfig * @param array|null $aliases * @param array|null $skippedOrigins */ protected function checkSchema(ConfigInterface $extendConfig, $aliases, array $skippedOrigins = null) { $extendProvider = $this->em->getExtendConfigProvider(); $className = $extendConfig->getId()->getClassName(); $doctrine = []; $entityName = $className; if (ExtendHelper::isCustomEntity($className)) { $type = 'Custom'; $tableName = $extendConfig->get('table'); if (!$tableName) { $tableName = $this->nameGenerator->generateCustomEntityTableName($className); } $doctrine[$entityName] = ['type' => 'entity', 'table' => $tableName]; // add 'id' field only for Custom entity without inheritance if (!$extendConfig->has('inherit')) { $doctrine[$entityName]['fields'] = ['id' => ['type' => 'integer', 'id' => true, 'generator' => ['strategy' => 'AUTO']]]; } } else { $type = 'Extend'; $entityName = $extendConfig->get('extend_class'); $doctrine[$entityName] = ['type' => 'mappedSuperclass', 'fields' => []]; } $schema = $extendConfig->get('schema'); $properties = []; $relationProperties = $schema ? $schema['relation'] : []; $defaultProperties = []; $addRemoveMethods = []; $fieldConfigs = $extendProvider->filter($this->createOriginFilterCallback($skippedOrigins), $className, true); foreach ($fieldConfigs as $fieldConfig) { $this->checkFields($entityName, $fieldConfig, $relationProperties, $defaultProperties, $properties, $doctrine); $extendProvider->persist($fieldConfig); } $relations = $extendConfig->get('relation', false, []); foreach ($relations as &$relation) { if (!$relation['field_id']) { continue; } $relation['assign'] = true; if ($relation['field_id']->getFieldType() !== RelationType::MANY_TO_ONE) { $fieldName = $relation['field_id']->getFieldName(); $addRemoveMethods[$fieldName]['self'] = $fieldName; if ($relation['target_field_id']) { $addRemoveMethods[$fieldName]['target'] = $relation['target_field_id']->getFieldName(); $addRemoveMethods[$fieldName]['is_target_addremove'] = $relation['field_id']->getFieldType() === RelationType::MANY_TO_MANY; } } $this->updateRelationValues($relation['target_entity'], $relation['field_id']); } $extendConfig->set('relation', $relations); $schema = ['class' => $className, 'entity' => $entityName, 'type' => $type, 'property' => $properties, 'relation' => $relationProperties, 'default' => $defaultProperties, 'addremove' => $addRemoveMethods, 'doctrine' => $doctrine]; if ($type == 'Extend') { $parentClassName = get_parent_class($className); if ($parentClassName == $entityName) { $parentClassName = $aliases[$entityName]; } $schema['parent'] = $parentClassName; $schema['inherit'] = get_parent_class($parentClassName); } elseif ($extendConfig->has('inherit')) { $schema['inherit'] = $extendConfig->get('inherit'); } $extendConfig->set('schema', $schema); $extendProvider->persist($extendConfig); }
/** * @param string $className * @param string $mode * @param array $configs * @throws \LogicException */ protected function createEntityModel($className, $mode, array $configs) { if (!ExtendHelper::isCustomEntity($className)) { throw new \LogicException(sprintf('A new model can be created for custom entity only. Class: %s.', $className)); } $this->logger->info(sprintf('Create entity "%s".', $className), ['configs' => $configs]); $this->configManager->createConfigEntityModel($className, $mode); $this->updateConfigs($configs, $className); $extendConfigProvider = $this->configManager->getProvider('extend'); $extendConfig = $extendConfigProvider->getConfig($className); $extendConfig->set('state', ExtendScope::STATE_NEW); $this->configManager->persist($extendConfig); }
/** * Builds a table name for a custom entity * The custom entity is an entity which has no PHP class in any bundle. The definition of such entity is * created automatically in Symfony cache * * @param string $entityClassName * @return string * @throws \InvalidArgumentException */ public function generateCustomEntityTableName($entityClassName) { if (!ExtendHelper::isCustomEntity($entityClassName)) { throw new \InvalidArgumentException(sprintf('The "%s" must be a custom entity.', $entityClassName)); } $entityName = substr($entityClassName, strlen(ExtendHelper::ENTITY_NAMESPACE)); if (empty($entityName) || !preg_match('/^[A-Za-z][\\w]+$/', $entityName)) { throw new \InvalidArgumentException(sprintf('Invalid entity name. Class: %s.', $entityClassName)); } if (strlen($entityName) > $this->getMaxCustomEntityNameSize()) { throw new \InvalidArgumentException(sprintf('Entity name length must be less or equal %d characters. Class: %s.', $this->getMaxCustomEntityNameSize(), $entityClassName)); } return self::CUSTOM_TABLE_PREFIX . strtolower($entityName); }
/** * @param string $targetClass The FQCN of the activity target entity * @param int $targetId The identifier of the activity target entity * * @return string|null */ protected function getContextLink($targetClass, $targetId) { $metadata = $this->configManager->getEntityMetadata($targetClass); $link = null; if ($metadata) { try { $route = $metadata->getRoute('view', true); } catch (\LogicException $exception) { // Need for cases when entity does not have route. return null; } $link = $this->router->generate($route, ['id' => $targetId]); } elseif (ExtendHelper::isCustomEntity($targetClass)) { $safeClassName = $this->entityClassNameHelper->getUrlSafeClassName($targetClass); // Generate view link for the custom entity $link = $this->router->generate('oro_entity_view', ['id' => $targetId, 'entityName' => $safeClassName]); } return $link; }
/** * @dataProvider isCustomEntityProvider */ public function testIsCustomEntity($className, $expected) { $this->assertEquals($expected, ExtendHelper::isCustomEntity($className)); }
/** * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * * @param ConfigInterface $extendConfig * @param ConfigProvider $configProvider * @param array|null $aliases * @param callable|null $filter function (ConfigInterface $config) : bool */ protected function checkSchema(ConfigInterface $extendConfig, ConfigProvider $configProvider, $aliases, $filter = null) { $className = $extendConfig->getId()->getClassName(); $doctrine = []; $entityName = $className; if (ExtendHelper::isCustomEntity($className)) { $type = 'Custom'; $tableName = $extendConfig->get('table'); if (!$tableName) { $tableName = $this->nameGenerator->generateCustomEntityTableName($className); } $doctrine[$entityName] = ['type' => 'entity', 'table' => $tableName]; // add 'id' field only for Custom entity without inheritance if (!$extendConfig->has('inherit')) { $doctrine[$entityName]['fields'] = ['id' => ['type' => 'integer', 'id' => true, 'generator' => ['strategy' => 'AUTO']]]; } } else { $type = 'Extend'; $entityName = $extendConfig->get('extend_class'); $doctrine[$entityName] = ['type' => 'mappedSuperclass', 'fields' => []]; } $schema = $extendConfig->get('schema', false, []); $properties = isset($schema['property']) && null !== $filter ? $schema['property'] : []; $relationProperties = isset($schema['relation']) && null !== $filter ? $schema['relation'] : []; $defaultProperties = isset($schema['default']) && null !== $filter ? $schema['default'] : []; $addRemoveMethods = isset($schema['addremove']) && null !== $filter ? $schema['addremove'] : []; $fieldConfigs = null === $filter ? $configProvider->getConfigs($className, true) : $configProvider->filter($filter, $className, true); foreach ($fieldConfigs as $fieldConfig) { $this->updateFieldState($fieldConfig); $this->checkFieldSchema($entityName, $fieldConfig, $relationProperties, $defaultProperties, $properties, $doctrine); } $relations = $extendConfig->get('relation', false, []); foreach ($relations as $relation) { /** @var FieldConfigId $fieldId */ $fieldId = $relation['field_id']; if (!$fieldId) { continue; } $fieldName = $fieldId->getFieldName(); $isDeleted = $configProvider->hasConfig($fieldId->getClassName(), $fieldName) ? $configProvider->getConfig($fieldId->getClassName(), $fieldName)->is('is_deleted') : false; if (!isset($relationProperties[$fieldName])) { $relationProperties[$fieldName] = []; if ($isDeleted) { $relationProperties[$fieldName]['private'] = true; } } if (!$isDeleted && $fieldId->getFieldType() !== RelationType::MANY_TO_ONE) { $addRemoveMethods[$fieldName]['self'] = $fieldName; /** @var FieldConfigId $targetFieldId */ $targetFieldId = $relation['target_field_id']; if ($targetFieldId) { $fieldType = $fieldId->getFieldType(); $addRemoveMethods[$fieldName]['target'] = $targetFieldId->getFieldName(); $addRemoveMethods[$fieldName]['is_target_addremove'] = $fieldType === RelationType::MANY_TO_MANY; } } } $schema = ['class' => $className, 'entity' => $entityName, 'type' => $type, 'property' => $properties, 'relation' => $relationProperties, 'default' => $defaultProperties, 'addremove' => $addRemoveMethods, 'doctrine' => $doctrine]; if ($type === 'Extend') { $parentClassName = get_parent_class($className); if ($parentClassName === $entityName) { $parentClassName = $aliases[$entityName]; } $schema['parent'] = $parentClassName; $schema['inherit'] = get_parent_class($parentClassName); } elseif ($extendConfig->has('inherit')) { $schema['inherit'] = $extendConfig->get('inherit'); } $extendConfig->set('schema', $schema); $this->configManager->persist($extendConfig); }
/** * Returns the context for the given activity class and id * * @param string $class The FQCN of the activity entity * @param $id * * @return array */ public function getActivityContext($class, $id) { $currentUser = $this->securityTokenStorage->getToken()->getUser(); $userClass = ClassUtils::getClass($currentUser); $entity = $this->doctrineHelper->getEntity($class, $id); $result = []; if (!$entity || !$entity instanceof ActivityInterface) { return $result; } $targets = $entity->getActivityTargetEntities(); $entityProvider = $this->configManager->getProvider('entity'); foreach ($targets as $target) { $targetClass = ClassUtils::getClass($target); $targetId = $target->getId(); if ($userClass === $targetClass && $currentUser->getId() === $targetId) { continue; } $item = []; $config = $entityProvider->getConfig($targetClass); $metadata = $this->configManager->getEntityMetadata($targetClass); $safeClassName = $this->entityClassNameHelper->getUrlSafeClassName($targetClass); $link = null; if ($metadata) { $link = $this->router->generate($metadata->getRoute(), ['id' => $targetId]); } elseif ($link === null && ExtendHelper::isCustomEntity($targetClass)) { // Generate view link for the custom entity $link = $this->router->generate('oro_entity_view', ['id' => $targetId, 'entityName' => $safeClassName]); } if ($fields = $this->mapper->getEntityMapParameter($targetClass, 'title_fields')) { $text = []; foreach ($fields as $field) { $text[] = $this->mapper->getFieldValue($target, $field); } $item['title'] = implode(' ', $text); } else { $item['title'] = $this->translator->trans('oro.entity.item', ['%id%' => $targetId]); } $item['activityClassAlias'] = $this->entityAliasResolver->getPluralAlias($class); $item['entityId'] = $id; $item['targetId'] = $targetId; $item['targetClassName'] = $safeClassName; $item['icon'] = $config->get('icon'); $item['link'] = $link; $result[] = $item; } return $result; }
/** * @param string $className The entity class name * @param int $id The entity id * * @return string|null */ public function getViewLink($className, $id) { $route = $this->getClassRoute($className, 'view'); if ($route) { return $this->router->generate($route, ['id' => $id]); } // Generate view link for the custom entity if (ExtendHelper::isCustomEntity($className)) { return $this->router->generate('oro_entity_view', ['id' => $id, 'entityName' => $this->entityClassNameHelper->getUrlSafeClassName($className)]); } return null; }