From 9ec2b26d3845272f5271302c6514bbdad33bfd97 Mon Sep 17 00:00:00 2001 From: Taras Machyshyn Date: Fri, 13 Dec 2013 19:04:56 +0200 Subject: [PATCH] ORM metadata convertation and database Schema building --- application/Espo/Core/Application.php | 18 +- .../Core/Doctrine/Converter/Association.php | 197 ----- application/Espo/Core/Doctrine/Helper.php | 101 --- .../ORM/Mapping/Driver/EspoPHPDriver.php | 679 ------------------ .../Espo/Core/Loaders/EntityManager.php | 7 +- application/Espo/Core/Utils/Api/Auth.php | 7 +- application/Espo/Core/Utils/Config.php | 15 +- .../Espo/Core/Utils/Database/Converter.php | 100 +++ .../Database/Converters/Orm.php} | 219 +++--- .../Core/Utils/Database/Converters/Schema.php | 112 +++ .../Core/Utils/Database/FieldTypes/Bool.php | 45 ++ .../Core/Utils/Database/FieldTypes/Int.php | 35 + .../Database/FieldTypes}/Password.php | 13 +- .../Utils/Database/FieldTypes/Varchar.php | 29 + .../Link.php => Utils/Database/Links.php} | 86 +-- .../Espo/Core/Utils/Database/Relations.php | 179 +++++ .../Espo/Core/Utils/Database/Schema.php | 182 +++++ application/Espo/Core/Utils/File/Manager.php | 4 + application/Espo/Core/Utils/Metadata.php | 39 +- application/Espo/Core/Utils/Util.php | 13 + .../Espo/Core/defaults/systemConfig.php | 2 - application/Espo/Entities/Bug.php | 122 ---- application/Espo/Entities/BugRepository.php | 47 -- application/Espo/Entities/User.php | 8 +- .../Crm/Resources/metadata/defs/Contact.json | 1 - .../Crm/Resources/metadata/defs/Product.json | 17 - .../Crm/Resources/metadata/defs/unset.json | 5 - application/Espo/ORM/EntityFactory.php | 52 +- application/Espo/ORM/EntityManager.php | 2 +- .../Espo/Resources/metadata/defs/Bug.json | 35 - .../Espo/Resources/metadata/defs/User.json | 26 - .../Resources/metadata/entityDefs/User.json | 3 + .../metadata/fields/autoincrement.json | 2 +- .../Espo/Resources/metadata/fields/base.json | 2 +- .../Espo/Resources/metadata/fields/bool.json | 3 - .../Resources/metadata/fields/duration.json | 10 +- .../Espo/Resources/metadata/fields/email.json | 2 +- .../Espo/Resources/metadata/fields/enum.json | 2 +- .../Resources/metadata/fields/enumInt.json | 2 +- .../Espo/Resources/metadata/fields/int.json | 3 - .../Espo/Resources/metadata/fields/link.json | 3 + .../metadata/fields/linkMultiple.json | 3 + .../Resources/metadata/fields/linkParent.json | 3 + .../Resources/metadata/fields/multienum.json | 3 - .../Espo/Resources/metadata/fields/phone.json | 2 +- .../Espo/Resources/metadata/fields/url.json | 2 +- .../Resources/metadata/fields/varchar.json | 3 - testAuth.php | 10 +- .../Espo/Core/Doctrine/EspoConverterTest.php | 45 -- .../Core/Utils/Database/RelationsTest.php | 477 ++++++++++++ 50 files changed, 1422 insertions(+), 1555 deletions(-) delete mode 100644 application/Espo/Core/Doctrine/Converter/Association.php delete mode 100644 application/Espo/Core/Doctrine/Helper.php delete mode 100644 application/Espo/Core/Doctrine/ORM/Mapping/Driver/EspoPHPDriver.php create mode 100644 application/Espo/Core/Utils/Database/Converter.php rename application/Espo/Core/{Doctrine/Converter/Base.php => Utils/Database/Converters/Orm.php} (56%) create mode 100644 application/Espo/Core/Utils/Database/Converters/Schema.php create mode 100644 application/Espo/Core/Utils/Database/FieldTypes/Bool.php create mode 100644 application/Espo/Core/Utils/Database/FieldTypes/Int.php rename application/Espo/Core/{Doctrine/Types => Utils/Database/FieldTypes}/Password.php (88%) create mode 100644 application/Espo/Core/Utils/Database/FieldTypes/Varchar.php rename application/Espo/Core/{Doctrine/Converter/Link.php => Utils/Database/Links.php} (52%) create mode 100644 application/Espo/Core/Utils/Database/Relations.php create mode 100644 application/Espo/Core/Utils/Database/Schema.php delete mode 100644 application/Espo/Entities/Bug.php delete mode 100644 application/Espo/Entities/BugRepository.php delete mode 100644 application/Espo/Modules/Crm/Resources/metadata/defs/Contact.json delete mode 100644 application/Espo/Modules/Crm/Resources/metadata/defs/Product.json delete mode 100644 application/Espo/Modules/Crm/Resources/metadata/defs/unset.json delete mode 100644 application/Espo/Resources/metadata/defs/Bug.json delete mode 100644 application/Espo/Resources/metadata/defs/User.json delete mode 100644 tests/Espo/Core/Doctrine/EspoConverterTest.php create mode 100644 tests/Espo/Core/Utils/Database/RelationsTest.php diff --git a/application/Espo/Core/Application.php b/application/Espo/Core/Application.php index 4e26402246..396da464de 100644 --- a/application/Espo/Core/Application.php +++ b/application/Espo/Core/Application.php @@ -23,7 +23,7 @@ class Application $this->container = new Container(); $GLOBALS['log'] = $this->log = $this->container->get('log'); - + set_error_handler(array($this->getLog(), 'catchError'), E_ALL); set_exception_handler(array($this->getLog(), 'catchException')); @@ -79,15 +79,13 @@ class Application $this->getMetadata()->init($isNotCached); if ($isNotCached) { - $doctrineConverter = new \Espo\Core\Doctrine\Converter\Base($this->container->get('entityManager'), $this->getMetadata(), $this->container->get('fileManager')); + $schema = new \Espo\Core\Utils\Database\Schema($this->container->get('config'), $this->getMetadata(), $this->container->get('fileManager')); - if ($doctrineConverter->process()) { - try{ - $doctrineConverter->getDoctrineHelper()->rebuildDatabase(); - } catch (\Exception $e) { - $GLOBALS['log']->add('EXCEPTION', 'Fault to rebuildDatabase'.'. Details: '.$e->getMessage()); - } - } + try{ + $schema->rebuild(); + } catch (\Exception $e) { + $GLOBALS['log']->add('EXCEPTION', 'Fault to rebuild database schema'.'. Details: '.$e->getMessage()); + } } } @@ -96,12 +94,10 @@ class Application $container = $this->getContainer(); $slim = $this->getSlim(); $serviceFactory = $this->getServiceFactory(); - $auth = new \Espo\Core\Utils\Api\Auth($container->get('entityManager'), $container); $this->getSlim()->add($auth); - $this->getSlim()->hook('slim.before.dispatch', function () use ($slim, $container) { $conditions = $slim->router()->getCurrentRoute()->getConditions(); diff --git a/application/Espo/Core/Doctrine/Converter/Association.php b/application/Espo/Core/Doctrine/Converter/Association.php deleted file mode 100644 index a4162eeea4..0000000000 --- a/application/Espo/Core/Doctrine/Converter/Association.php +++ /dev/null @@ -1,197 +0,0 @@ - array( - 'manyToOne' => array( - $params['usLinkName'] => array( - 'targetEntity' => $params['targetEntity'], - 'joinColumn' => array( - 'name' => $params['usLinkName'].'_id', - 'referencedColumnName' => 'id', - ), - ), - ), - ), - ); - } - - - public function oneToManyUnidirectionalWithJoinTable($params, $foreignParams) - { - return array ( - $params['entityName'] => - array ( - 'manyToMany' => - array ( - $params['usLinkName'] => - array ( - 'targetEntity' => $params['targetEntity'], - 'joinTable' => - array ( - 'name' => $params['joinTable'], - 'joinColumns' => - array ( - $params['usEntityName'].'_id' => - array ( - 'referencedColumnName' => 'id', - ), - ), - 'inverseJoinColumns' => - array ( - $foreignParams['usEntityName'].'_id' => - array ( - 'referencedColumnName' => 'id', - 'unique' => true, - ), - ), - ), - ), - ), - ), - ); - } - - - public function manyToManyBidirectional($params, $foreignParams) - { - return array ( - $params['entityName'] => - array ( - 'manyToMany' => - array ( - $params['usLinkName'] => - array ( - 'targetEntity' => $params['targetEntity'], - 'inversedBy' => $foreignParams['usLinkName'], - 'joinTable' => - array ( - 'name' => $params['joinTable'], - 'joinColumns' => - array ( - $params['usEntityName'].'_id' => - array ( - 'referencedColumnName' => 'id', - ), - ), - 'inverseJoinColumns' => - array ( - $foreignParams['usEntityName'].'_id' => - array ( - 'referencedColumnName' => 'id', - ), - ), - ), - ), - ), - ), - - $foreignParams['entityName'] => - array ( - 'manyToMany' => - array ( - $foreignParams['usLinkName'] => - array ( - 'targetEntity' => $foreignParams['targetEntity'], - 'mappedBy' => $params['usLinkName'], - ), - ), - ), - ); - } - - public function oneToOneUnidirectional($params, $foreignParams) - { - return array ( - $params['entityName'] => - array ( - 'oneToOne' => - array ( - $params['usLinkName'] => - array ( - 'targetEntity' => $params['targetEntity'], - 'joinColumn' => - array ( - 'name' => $params['usLinkName'].'_id', - 'referencedColumnName' => 'id', - ), - ), - ), - ), - ); - } - - public function oneToOneBidirectional($params, $foreignParams) - { - return array ( - $params['entityName'] => - array ( - 'oneToOne' => - array ( - $params['usLinkName'] => - array ( - 'targetEntity' => $params['targetEntity'], - 'mappedBy' => $foreignParams['usLinkName'], - ), - ), - ), - - $foreignParams['entityName'] => - array ( - 'oneToOne' => - array ( - $foreignParams['usLinkName'] => - array ( - 'targetEntity' => $foreignParams['targetEntity'], - 'inversedBy' => $params['usLinkName'], - 'joinColumn' => - array ( - 'name' => $params['usLinkName'].'_id', - 'referencedColumnName' => 'id', - ), - ), - ), - ), - ); - } - - public function oneToManySelfReferencing($params, $foreignParams) - { - return array ( - 'Category' => - array ( - 'type' => 'entity', - 'oneToMany' => - array ( - 'children' => - array ( - 'targetEntity' => 'Category', - 'mappedBy' => 'parent', - ), - ), - 'manyToOne' => - array ( - 'parent' => - array ( - 'targetEntity' => 'Category', - 'inversedBy' => 'children', - ), - ), - ), - ); - } - - - - - - - -} \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/Helper.php b/application/Espo/Core/Doctrine/Helper.php deleted file mode 100644 index 6ceaab3578..0000000000 --- a/application/Espo/Core/Doctrine/Helper.php +++ /dev/null @@ -1,101 +0,0 @@ -entityManager = $entityManager; - - $this->schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->getEntityManager()); - $this->entityGenerator = new \Doctrine\ORM\Tools\EntityGenerator(); - - $this->disconnectedClassMetadataFactory = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory(); - $this->disconnectedClassMetadataFactory->setEntityManager($this->getEntityManager()); // $em is EntityManager instance - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - protected function getSchemaTool() - { - return $this->schemaTool; - } - - protected function getDisconnectedClassMetadataFactory() - { - return $this->disconnectedClassMetadataFactory; - } - - protected function getEntityGenerator() - { - return $this->entityGenerator; - } - - - - /** - * Rebuild a database accordinly to metadata - * - * @return bool - */ - public function rebuildDatabase() - { - $GLOBALS['log']->add('DEBUG', 'EspoConverter:rebuildDatabase() - start rebuild database'); - - $classes = $this->getDisconnectedClassMetadataFactory()->getAllMetadata(); - $this->getSchemaTool()->updateSchema($classes); - - $GLOBALS['log']->add('DEBUG', 'EspoConverter:rebuildDatabase() - end rebuild database'); - - return true; //always true, because updateSchema just returns the VOID - } - - - /** - * Rebuild a database accordinly to metadata - * - * @return bool - */ - public function generateEntities($classNames) - { - if (!is_array($classNames)) { - $classNames= (array) $classNames; - } - - $metadata= array(); - foreach($classNames as $className) { - $metadata[]= $this->getDisconnectedClassMetadataFactory()->getMetadataFor($className); - } - - if (!empty($metadata)) { - $GLOBALS['log']->add('DEBUG', 'EspoConverter:generateEntities() - start generate Entities'); - - $this->getEntityGenerator()->setGenerateAnnotations(false); - $this->getEntityGenerator()->setGenerateStubMethods(true); - $this->getEntityGenerator()->setRegenerateEntityIfExists(false); - $this->getEntityGenerator()->setUpdateEntityIfExists(false); - $this->getEntityGenerator()->generate($metadata, 'application'); - - $GLOBALS['log']->add('DEBUG', 'EspoConverter:generateEntities() - end generate Entities'); - - return true; //always true, because generate just returns the VOID - } - - return false; - } - - -} \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/ORM/Mapping/Driver/EspoPHPDriver.php b/application/Espo/Core/Doctrine/ORM/Mapping/Driver/EspoPHPDriver.php deleted file mode 100644 index 0ca1637b8c..0000000000 --- a/application/Espo/Core/Doctrine/ORM/Mapping/Driver/EspoPHPDriver.php +++ /dev/null @@ -1,679 +0,0 @@ -getElement($className); - - if ($element['type'] == 'entity') { - if (isset($element['repositoryClass'])) { - $metadata->setCustomRepositoryClass($element['repositoryClass']); - } - if (isset($element['readOnly']) && $element['readOnly'] == true) { - $metadata->markReadOnly(); - } - } else if ($element['type'] == 'mappedSuperclass') { - $metadata->setCustomRepositoryClass( - isset($element['repositoryClass']) ? $element['repositoryClass'] : null - ); - $metadata->isMappedSuperclass = true; - } else { - throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); - } - - // Evaluate root level properties - $table = array(); - if (isset($element['table'])) { - $table['name'] = $element['table']; - } - $metadata->setPrimaryTable($table); - - // Evaluate named queries - if (isset($element['namedQueries'])) { - foreach ($element['namedQueries'] as $name => $queryMapping) { - if (is_string($queryMapping)) { - $queryMapping = array('query' => $queryMapping); - } - - if ( ! isset($queryMapping['name'])) { - $queryMapping['name'] = $name; - } - - $metadata->addNamedQuery($queryMapping); - } - } - - // Evaluate named native queries - if (isset($element['namedNativeQueries'])) { - foreach ($element['namedNativeQueries'] as $name => $mappingElement) { - if (!isset($mappingElement['name'])) { - $mappingElement['name'] = $name; - } - $metadata->addNamedNativeQuery(array( - 'name' => $mappingElement['name'], - 'query' => isset($mappingElement['query']) ? $mappingElement['query'] : null, - 'resultClass' => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null, - 'resultSetMapping' => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null, - )); - } - } - - // Evaluate sql result set mappings - if (isset($element['sqlResultSetMappings'])) { - foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) { - if (!isset($resultSetMapping['name'])) { - $resultSetMapping['name'] = $name; - } - - $entities = array(); - $columns = array(); - if (isset($resultSetMapping['entityResult'])) { - foreach ($resultSetMapping['entityResult'] as $entityResultElement) { - $entityResult = array( - 'fields' => array(), - 'entityClass' => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null, - 'discriminatorColumn' => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null, - ); - - if (isset($entityResultElement['fieldResult'])) { - foreach ($entityResultElement['fieldResult'] as $fieldResultElement) { - $entityResult['fields'][] = array( - 'name' => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null, - 'column' => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null, - ); - } - } - - $entities[] = $entityResult; - } - } - - - if (isset($resultSetMapping['columnResult'])) { - foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) { - $columns[] = array( - 'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null, - ); - } - } - - $metadata->addSqlResultSetMapping(array( - 'name' => $resultSetMapping['name'], - 'entities' => $entities, - 'columns' => $columns - )); - } - } - - /* not implemented specially anyway. use table = schema.table - if (isset($element['schema'])) { - $metadata->table['schema'] = $element['schema']; - }*/ - - if (isset($element['inheritanceType'])) { - $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType']))); - - if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { - // Evaluate discriminatorColumn - if (isset($element['discriminatorColumn'])) { - $discrColumn = $element['discriminatorColumn']; - $metadata->setDiscriminatorColumn(array( - 'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null, - 'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null, - 'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null, - 'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string)$discrColumn['columnDefinition'] : null - )); - } else { - $metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255)); - } - - // Evaluate discriminatorMap - if (isset($element['discriminatorMap'])) { - $metadata->setDiscriminatorMap($element['discriminatorMap']); - } - } - } - - - // Evaluate changeTrackingPolicy - if (isset($element['changeTrackingPolicy'])) { - $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' - . strtoupper($element['changeTrackingPolicy']))); - } - - // Evaluate indexes - if (isset($element['indexes'])) { - foreach ($element['indexes'] as $name => $index) { - if ( ! isset($index['name'])) { - $index['name'] = $name; - } - - if (is_string($index['columns'])) { - $columns = explode(',', $index['columns']); - $columns = array_map('trim', $columns); - } else { - $columns = $index['columns']; - } - - $metadata->table['indexes'][$index['name']] = array( - 'columns' => $columns - ); - } - } - - // Evaluate uniqueConstraints - if (isset($element['uniqueConstraints'])) { - foreach ($element['uniqueConstraints'] as $name => $unique) { - if ( ! isset($unique['name'])) { - $unique['name'] = $name; - } - - if (is_string($unique['columns'])) { - $columns = explode(',', $unique['columns']); - $columns = array_map('trim', $columns); - } else { - $columns = $unique['columns']; - } - - $metadata->table['uniqueConstraints'][$unique['name']] = array( - 'columns' => $columns - ); - } - } - - if (isset($element['options'])) { - $metadata->table['options'] = $element['options']; - } - - $associationIds = array(); - if (isset($element['id'])) { - // Evaluate identifier settings - foreach ($element['id'] as $name => $idElement) { - if (isset($idElement['associationKey']) && $idElement['associationKey'] == true) { - $associationIds[$name] = true; - continue; - } - - $mapping = array( - 'id' => true, - 'fieldName' => $name - ); - - if (isset($idElement['type'])) { - $mapping['type'] = $idElement['type']; - } - - if (isset($idElement['column'])) { - $mapping['columnName'] = $idElement['column']; - } - - if (isset($idElement['length'])) { - $mapping['length'] = $idElement['length']; - } - - if (isset($idElement['columnDefinition'])) { - $mapping['columnDefinition'] = $idElement['columnDefinition']; - } - - $metadata->mapField($mapping); - - if (isset($idElement['generator'])) { - $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' - . strtoupper($idElement['generator']['strategy']))); - } - // Check for SequenceGenerator/TableGenerator definition - if (isset($idElement['sequenceGenerator'])) { - $metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']); - } else if (isset($idElement['customIdGenerator'])) { - $customGenerator = $idElement['customIdGenerator']; - $metadata->setCustomGeneratorDefinition(array( - 'class' => (string) $customGenerator['class'] - )); - } else if (isset($idElement['tableGenerator'])) { - throw MappingException::tableIdGeneratorNotImplemented($className); - } - } - } - - // Evaluate fields - if (isset($element['fields'])) { - foreach ($element['fields'] as $name => $fieldMapping) { - - $mapping = $this->columnToArray($name, $fieldMapping); - - if (isset($fieldMapping['id'])) { - $mapping['id'] = true; - if (isset($fieldMapping['generator']['strategy'])) { - $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' - . strtoupper($fieldMapping['generator']['strategy']))); - } - } - - if (isset($mapping['version'])) { - $metadata->setVersionMapping($mapping); - unset($mapping['version']); - } - - $metadata->mapField($mapping); - } - } - - // Evaluate oneToOne relationships - if (isset($element['oneToOne'])) { - foreach ($element['oneToOne'] as $name => $oneToOneElement) { - $mapping = array( - 'fieldName' => $name, - 'targetEntity' => $oneToOneElement['targetEntity'] - ); - - if (isset($associationIds[$mapping['fieldName']])) { - $mapping['id'] = true; - } - - if (isset($oneToOneElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']); - } - - if (isset($oneToOneElement['mappedBy'])) { - $mapping['mappedBy'] = $oneToOneElement['mappedBy']; - } else { - if (isset($oneToOneElement['inversedBy'])) { - $mapping['inversedBy'] = $oneToOneElement['inversedBy']; - } - - $joinColumns = array(); - - if (isset($oneToOneElement['joinColumn'])) { - $joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']); - } else if (isset($oneToOneElement['joinColumns'])) { - foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $joinColumnName; - } - - $joinColumns[] = $this->joinColumnToArray($joinColumnElement); - } - } - - $mapping['joinColumns'] = $joinColumns; - } - - if (isset($oneToOneElement['cascade'])) { - $mapping['cascade'] = $oneToOneElement['cascade']; - } - - if (isset($oneToOneElement['orphanRemoval'])) { - $mapping['orphanRemoval'] = (bool)$oneToOneElement['orphanRemoval']; - } - - $metadata->mapOneToOne($mapping); - } - } - - // Evaluate oneToMany relationships - if (isset($element['oneToMany'])) { - foreach ($element['oneToMany'] as $name => $oneToManyElement) { - $mapping = array( - 'fieldName' => $name, - 'targetEntity' => $oneToManyElement['targetEntity'], - 'mappedBy' => $oneToManyElement['mappedBy'] - ); - - if (isset($oneToManyElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']); - } - - if (isset($oneToManyElement['cascade'])) { - $mapping['cascade'] = $oneToManyElement['cascade']; - } - - if (isset($oneToManyElement['orphanRemoval'])) { - $mapping['orphanRemoval'] = (bool)$oneToManyElement['orphanRemoval']; - } - - if (isset($oneToManyElement['orderBy'])) { - $mapping['orderBy'] = $oneToManyElement['orderBy']; - } - - if (isset($oneToManyElement['indexBy'])) { - $mapping['indexBy'] = $oneToManyElement['indexBy']; - } - - $metadata->mapOneToMany($mapping); - } - } - - // Evaluate manyToOne relationships - if (isset($element['manyToOne'])) { - foreach ($element['manyToOne'] as $name => $manyToOneElement) { - $mapping = array( - 'fieldName' => $name, - 'targetEntity' => $manyToOneElement['targetEntity'] - ); - - if (isset($associationIds[$mapping['fieldName']])) { - $mapping['id'] = true; - } - - if (isset($manyToOneElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']); - } - - if (isset($manyToOneElement['inversedBy'])) { - $mapping['inversedBy'] = $manyToOneElement['inversedBy']; - } - - $joinColumns = array(); - - if (isset($manyToOneElement['joinColumn'])) { - $joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']); - } else if (isset($manyToOneElement['joinColumns'])) { - foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $joinColumnName; - } - - $joinColumns[] = $this->joinColumnToArray($joinColumnElement); - } - } - - $mapping['joinColumns'] = $joinColumns; - - if (isset($manyToOneElement['cascade'])) { - $mapping['cascade'] = $manyToOneElement['cascade']; - } - - $metadata->mapManyToOne($mapping); - } - } - - // Evaluate manyToMany relationships - if (isset($element['manyToMany'])) { - foreach ($element['manyToMany'] as $name => $manyToManyElement) { - $mapping = array( - 'fieldName' => $name, - 'targetEntity' => $manyToManyElement['targetEntity'] - ); - - if (isset($manyToManyElement['fetch'])) { - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']); - } - - if (isset($manyToManyElement['mappedBy'])) { - $mapping['mappedBy'] = $manyToManyElement['mappedBy']; - } else if (isset($manyToManyElement['joinTable'])) { - - $joinTableElement = $manyToManyElement['joinTable']; - $joinTable = array( - 'name' => $joinTableElement['name'] - ); - - if (isset($joinTableElement['schema'])) { - $joinTable['schema'] = $joinTableElement['schema']; - } - - foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $joinColumnName; - } - - $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - - foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $joinColumnName; - } - - $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - - $mapping['joinTable'] = $joinTable; - } - - if (isset($manyToManyElement['inversedBy'])) { - $mapping['inversedBy'] = $manyToManyElement['inversedBy']; - } - - if (isset($manyToManyElement['cascade'])) { - $mapping['cascade'] = $manyToManyElement['cascade']; - } - - if (isset($manyToManyElement['orderBy'])) { - $mapping['orderBy'] = $manyToManyElement['orderBy']; - } - - if (isset($manyToManyElement['indexBy'])) { - $mapping['indexBy'] = $manyToManyElement['indexBy']; - } - - if (isset($manyToManyElement['orphanRemoval'])) { - $mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval']; - } - - $metadata->mapManyToMany($mapping); - } - } - - // Evaluate associationOverride - if (isset($element['associationOverride']) && is_array($element['associationOverride'])) { - - foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) { - $override = array(); - - // Check for joinColumn - if (isset($associationOverrideElement['joinColumn'])) { - $joinColumns = array(); - foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $name; - } - $joinColumns[] = $this->joinColumnToArray($joinColumnElement); - } - $override['joinColumns'] = $joinColumns; - } - - // Check for joinTable - if (isset($associationOverrideElement['joinTable'])) { - - $joinTableElement = $associationOverrideElement['joinTable']; - $joinTable = array( - 'name' => $joinTableElement['name'] - ); - - if (isset($joinTableElement['schema'])) { - $joinTable['schema'] = $joinTableElement['schema']; - } - - foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $name; - } - - $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - - foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) { - if ( ! isset($joinColumnElement['name'])) { - $joinColumnElement['name'] = $name; - } - - $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); - } - - $override['joinTable'] = $joinTable; - } - - $metadata->setAssociationOverride($fieldName, $override); - } - } - - // Evaluate associationOverride - if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) { - - foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) { - $mapping = $this->columnToArray($fieldName, $attributeOverrideElement); - $metadata->setAttributeOverride($fieldName, $mapping); - } - } - - // Evaluate lifeCycleCallbacks - if (isset($element['lifecycleCallbacks'])) { - foreach ($element['lifecycleCallbacks'] as $type => $methods) { - foreach ($methods as $method) { - $metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type)); - } - } - } - - // populate ClassMetadataInfo instance from $data - - } - - /** - * Constructs a joinColumn mapping array based on the information - * found in the given join column element. - * - * @param array $joinColumnElement The array join column element - * @return array The mapping array. - */ - private function joinColumnToArray($joinColumnElement) - { - $joinColumn = array(); - if (isset($joinColumnElement['referencedColumnName'])) { - $joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName']; - } - - if (isset($joinColumnElement['name'])) { - $joinColumn['name'] = (string) $joinColumnElement['name']; - } - - if (isset($joinColumnElement['fieldName'])) { - $joinColumn['fieldName'] = (string) $joinColumnElement['fieldName']; - } - - if (isset($joinColumnElement['unique'])) { - $joinColumn['unique'] = (bool) $joinColumnElement['unique']; - } - - if (isset($joinColumnElement['nullable'])) { - $joinColumn['nullable'] = (bool) $joinColumnElement['nullable']; - } - - if (isset($joinColumnElement['onDelete'])) { - $joinColumn['onDelete'] = $joinColumnElement['onDelete']; - } - - if (isset($joinColumnElement['columnDefinition'])) { - $joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition']; - } - - return $joinColumn; - } - - /** - * Parse the given column as array - * - * @param string $fieldName - * @param array $column - * @return array - */ - private function columnToArray($fieldName, $column) - { - $mapping = array( - 'fieldName' => $fieldName - ); - - if (isset($column['type'])) { - $params = explode('(', $column['type']); - $column['type'] = $params[0]; - $mapping['type'] = $column['type']; - - if (isset($params[1])) { - $column['length'] = (integer) substr($params[1], 0, strlen($params[1]) - 1); - } - } - - if (isset($column['column'])) { - $mapping['columnName'] = $column['column']; - } - - if (isset($column['length'])) { - $mapping['length'] = $column['length']; - } - - if (isset($column['precision'])) { - $mapping['precision'] = $column['precision']; - } - - if (isset($column['scale'])) { - $mapping['scale'] = $column['scale']; - } - - if (isset($column['unique'])) { - $mapping['unique'] = (bool)$column['unique']; - } - - if (isset($column['options'])) { - $mapping['options'] = $column['options']; - } - - if (isset($column['nullable'])) { - $mapping['nullable'] = $column['nullable']; - } - - if (isset($column['version']) && $column['version']) { - $mapping['version'] = $column['version']; - } - - if (isset($column['columnDefinition'])) { - $mapping['columnDefinition'] = $column['columnDefinition']; - } - - return $mapping; - } - - /** - * {@inheritdoc} - */ - protected function loadMappingFile($file) - { - if (strpos($file, "\n") === false && is_file($file)) { - if (false === is_readable($file)) { - throw new MappingException(sprintf('File "%s" is not readable.', $file)); - } - - return include($file); - } - } - -} \ No newline at end of file diff --git a/application/Espo/Core/Loaders/EntityManager.php b/application/Espo/Core/Loaders/EntityManager.php index d3a9400e76..ceee12b80a 100644 --- a/application/Espo/Core/Loaders/EntityManager.php +++ b/application/Espo/Core/Loaders/EntityManager.php @@ -28,10 +28,11 @@ class EntityManager 'dbname' => $config->get('database.dbname'), 'user' => $config->get('database.user'), 'password' => $config->get('database.password'), + 'metadata' => $this->getContainer()->get('metadata')->getEspoMetadata(), ); - - $entityManager = new \Espo\Core\ORM\EntityManager($params); - $entityManager->setEspoMetadata($container->get('metadata')); + + $entityManager = new \Espo\Core\ORM\EntityManager($params); + $entityManager->setEspoMetadata($this->getContainer()->get('metadata')); return $entityManager; } diff --git a/application/Espo/Core/Utils/Api/Auth.php b/application/Espo/Core/Utils/Api/Auth.php index d44b8c15db..4765d7efd6 100644 --- a/application/Espo/Core/Utils/Api/Auth.php +++ b/application/Espo/Core/Utils/Api/Auth.php @@ -10,7 +10,7 @@ class Auth extends \Slim\Middleware private $container; - public function __construct(\Espo\Core\EntityManager $entityManager, \Espo\Core\Container $container) + public function __construct(\Espo\Core\ORM\EntityManager $entityManager, \Espo\Core\Container $container) { $this->entityManager = $entityManager; $this->container = $container; @@ -48,14 +48,13 @@ class Auth extends \Slim\Middleware $username = $authKey; $password = $authSec; - - $user = $this->entityManager->getRepository('User')->findOne(array('username' => $username)); + $user = $this->entityManager->getRepository('User')->findOne(array('userName' => $username)); if ($user) { if ($password == $user->get('password')) { $this->container->setUser($user); $isAuthenticated = true; } - } + } if ($isAuthenticated) { $this->next->call(); diff --git a/application/Espo/Core/Utils/Config.php b/application/Espo/Core/Utils/Config.php index 8ef378a9b7..dfc6e01865 100644 --- a/application/Espo/Core/Utils/Config.php +++ b/application/Espo/Core/Utils/Config.php @@ -52,13 +52,18 @@ class Config */ public function get($name) { - $contentObj = $this->getConfig(); + $keys = explode('.', $name); - if (isset($contentObj->$name)) { - return $contentObj->$name; - } + $lastBranch = $this->getConfig(); + foreach($keys as $keyName) { + if (isset($lastBranch->$keyName) && is_object($lastBranch)) { + $lastBranch = $lastBranch->$keyName; + } else { + return null; + } + } - return null; + return $lastBranch; } diff --git a/application/Espo/Core/Utils/Database/Converter.php b/application/Espo/Core/Utils/Database/Converter.php new file mode 100644 index 0000000000..a806e6def5 --- /dev/null +++ b/application/Espo/Core/Utils/Database/Converter.php @@ -0,0 +1,100 @@ +metadata = $metadata; + + $this->ormConverter = new Converters\Orm($this->metadata); + + $this->schemaConverter = new Converters\Schema(); + } + + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getOrmConverter() + { + return $this->ormConverter; + } + + protected function getSchemaConverter() + { + return $this->schemaConverter; + } + + + public function getSchemaFromMetadata() + { + return $this->schemaFromMetadata; + } + + protected function setSchemaFromMetadata(\Doctrine\DBAL\Schema\Schema $schema) + { + $this->schemaFromMetadata = $schema; + } + + /** + * Main method of convertation from metadata to orm metadata and database schema + * + * @return bool + */ + public function process() + { + $GLOBALS['log']->add('Debug', 'Converter:process() - Start: converting metadata to orm format and database schema'); + + $entityDefs = $this->getMetadata()->get('entityDefs'); + + $databaseMeta = array(); + foreach($entityDefs as $entityName => $entityMeta) { + + if (empty($entityMeta)) { + $GLOBALS['log']->add('ERROR', 'Converter:process(), Entity:'.$entityName.' - metadata cannot be converted into database format'); + continue; + } + + $databaseMeta = Util::merge($databaseMeta, $this->getOrmConverter()->process($entityName, $entityMeta, $entityDefs)); + } + + $schema = $this->getSchemaConverter()->process($databaseMeta, $entityDefs); + $this->setSchemaFromMetadata($schema); + + //save database meta to a file espoMetadata.php + $result = $this->getMetadata()->setEspoMetadata($databaseMeta); + + + $GLOBALS['log']->add('Debug', 'Converter:process() - End: converting metadata to orm format and database schema, result=['.$result.']'); + + return $result; + } + + + + +} + + +?> \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/Converter/Base.php b/application/Espo/Core/Utils/Database/Converters/Orm.php similarity index 56% rename from application/Espo/Core/Doctrine/Converter/Base.php rename to application/Espo/Core/Utils/Database/Converters/Orm.php index b5a81e5f3e..7d14bbd3cc 100644 --- a/application/Espo/Core/Doctrine/Converter/Base.php +++ b/application/Espo/Core/Utils/Database/Converters/Orm.php @@ -1,151 +1,81 @@ 255, + 'int' => 11, + ); + /* * //pair espo:doctrine */ protected $fieldAccordances = array( 'type' => 'type', - 'maxLength' => 'length', + 'maxLength' => 'len', 'default' => array( 'condition' => '^javascript:', 'conditionEquals' => false, 'value' => array( - 'options' => array ( - 'default' => '{0}', - ), + 'default' => '{0}', ), ), ); - /** - * @var array $meta - metadata array - */ - private $meta; - - - public function __construct(\Espo\Core\EntityManager $entityManager, \Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager) + public function __construct(\Espo\Core\Utils\Metadata $metadata) { - $this->entityManager = $entityManager; - $this->metadata = $metadata; - $this->fileManager = $fileManager; + $this->metadata = $metadata; - $this->doctrineHelper = new \Espo\Core\Doctrine\Helper($this->getEntityManager()->getWrapped()); - - $this->linkConverter = new \Espo\Core\Doctrine\Converter\Link($this->metadata); + $this->links = new \Espo\Core\Utils\Database\Links($this->metadata); } - protected function getEntityManager() - { - return $this->entityManager; - } protected function getMetadata() { return $this->metadata; } - protected function getFileManager() + protected function getLinks() { - return $this->fileManager; + return $this->links; } - protected function getDoctrineHelper() + + + //convertToDatabaseFormat + public function process($entityName, $entityMeta, $entityDefs) { - return $this->doctrineHelper; + $ormMeta = array(); + $ormMeta[$entityName] = array( + 'fields' => array( + ), + 'relations' => array( + ), + ); + + $ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta); + + $convertedLinks = $this->convertLinks($entityName, $entityMeta, $entityDefs); + + return Util::merge($ormMeta, $convertedLinks); } - protected function getLinkConverter() - { - return $this->linkConverter; - } - - /** - * Metadata conversion from Espo format into Doctrine - * - * @param object $meta - * - * @return bool - */ - - //public function process() - public function process() - { - //echo '
';
-		$GLOBALS['log']->add('Debug', 'Metadata:get() - converting to doctrine metadata');
-
-        $entityDefs = $this->getMetadata()->get('entityDefs');
-
- 		$convertedMeta = array();
-        foreach($entityDefs as $entityName => $entityMeta) {
-
-        	//echo '['.$entityName.']
'; - - if (empty($entityMeta)) { - $GLOBALS['log']->add('ERROR', 'EspoConverter:convert(), Entity:'.$entityName.' - metadata cannot be converted into Doctrine format'); - continue; - } - - $convertedMeta[$entityName] = array( - 'type' => 'entity', - 'table' => Util::fromCamelCase($entityName, '_'), //TODO: if need to convert to underscore - 'id' => array( - 'id' => array( - 'type' => 'string', - 'generator' => array('strategy' => 'UUID'), - ) - ), - ); - - $convertedMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta); - - $convertedLinks = $this->convertLinks($entityName, $entityMeta, $entityDefs, $convertedMeta); - - //$convertedMeta = Util::merge($convertedMeta, $convertedLinks); //for link is need to define for two entities at once - } - /*echo '
'; - print_r($convertedMeta); - exit;*/ - - return; - - //save doctrine meta to files - $cacheDir = $this->getMetadata()->getMetaConfig()->doctrineCache; - $this->getFileManager()->removeFilesInDir($cacheDir); //remove all existing files - - $result= true; - foreach ($convertedMeta as $entityName => $doctineMeta) { - $entityFullName = $this->getMetadata()->getEntityPath($entityName); - $doctrineMeta = array($entityFullName => $doctineMeta); - - //create a doctrine metadata file like "Espo.Entities.User.php" - $fileName = str_replace('\\', '.', $entityFullName).'.php'; - $result &= $this->getFileManager()->setContent($this->getFileManager()->getPHPFormat($doctrineMeta), $cacheDir, $fileName); - //END: create a doctrine metadata file - } - //END: save doctrine meta to files - - return $result; - } - /** * Metadata conversion from Espo format into Doctrine @@ -157,19 +87,27 @@ class Base */ protected function convertFields($entityName, $entityMeta) { - $outputMeta = array(); + $outputMeta = array( + 'id' => array( + 'type' => Entity::ID, + ), + ); + foreach($entityMeta['fields'] as $fieldName => $fieldParams) { - $fieldName = Util::fromCamelCase($fieldName, '_'); + //$fieldName = Util::fromCamelCase($fieldName, '_'); //check if "fields" option exists in $fieldMeta + $fieldParams['type'] = isset($fieldParams['type']) ? $fieldParams['type'] : ''; + $fieldTypeMeta = $this->getMetadata()->get('fields.'.$fieldParams['type']); if (isset($fieldTypeMeta['fields']) && is_array($fieldTypeMeta['fields'])) { $namingType = isset($fieldTypeMeta['naming']) ? $fieldTypeMeta['naming'] : $this->defaultNaming; foreach($fieldTypeMeta['fields'] as $subFieldName => $subFieldParams) { - $subFieldNameNaming = Util::fromCamelCase( Util::getNaming($fieldName, $subFieldName, $namingType, '_'), '_' ); + //$subFieldNameNaming = Util::fromCamelCase( Util::getNaming($fieldName, $subFieldName, $namingType, '_'), '_' ); + $subFieldNameNaming = Util::getNaming($fieldName, $subFieldName, $namingType); if (!isset($entityMeta['fields'][$subFieldNameNaming])) { $subFieldDefs = $this->convertField($entityName, $subFieldName, $subFieldParams); if ($subFieldDefs !== false) { @@ -186,16 +124,22 @@ class Base } } - /*Make actions for different types like "link", "linkMultiple", "linkParent" */ } + + if (!isset($outputMeta['deleted'])) { + $outputMeta['deleted'] = array( + 'type' => Entity::BOOL, + 'default' => 0, + ); + } + return $outputMeta; } - /*It can be moved to separate file*/ protected function convertField($entityName, $fieldName, array $fieldParams) { //set default type if exists @@ -206,34 +150,46 @@ class Base $fieldTypeMeta = $this->getMetadata()->get('fields.'.$fieldParams['type']); - //check if field need to be saved in database - if ( (isset($fieldParams['db']) && $fieldParams['db'] === false) || (isset($fieldTypeMeta['database']['db']) && !$fieldTypeMeta['database']['db'] === false) ) { - return false; - } //END: check if field need to be saved in database + //check if need to skip this field into database metadata + if (isset($fieldTypeMeta['database']['skip']) && $fieldTypeMeta['database']['skip'] === true) { + return false; + } $fieldDefs = $this->getInitValues($fieldParams); + //check if field need to be saved in database + //TODO change entytyDefs from db:false to notStorable:true + if ( (isset($fieldParams['db']) && $fieldParams['db'] === false) || (isset($fieldTypeMeta['database']['notStorable']) && !$fieldTypeMeta['database']['notStorable'] === true) ) { + $fieldDefs['notStorable'] = true; + } //END: check if field need to be saved in database + //merge database options from field definition if (isset($fieldTypeMeta['database'])) { $fieldDefs = Util::merge($fieldDefs, $fieldTypeMeta['database']); } + //check and set a field length + if (!isset($fieldDefs['len']) && in_array($fieldDefs['type'], array_keys($this->defaultLength))) { + $fieldDefs['len'] = $this->defaultLength[$fieldDefs['type']]; + } //END: check and set a field length + return $fieldDefs; } - protected function convertLinks($entityName, $entityMeta, array $entityDefs, array $convertedMeta) + protected function convertLinks($entityName, $entityMeta, array $entityDefs) { if (!isset($entityMeta['links'])) { return array(); } + $relationships = array(); foreach($entityMeta['links'] as $linkName => $linkParams) { //echo $linkName.'
'; //print_r($linkParams); - $linkEntityName = $this->getLinkConverter()->getLinkEntityName($entityName, $linkParams); + $linkEntityName = $this->getLinks()->getLinkEntityName($entityName, $linkParams); //print_r($entityDefs[$linkEntityName]['links']); //print_r($convertedMeta[$linkEntityName]); @@ -242,29 +198,38 @@ class Base $foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$linkEntityName]); - $method = $currentType; + $method = $currentType; + unset($reverseMethod); if ($foreignLink !== false) { $method .= '-'.$foreignLink['params']['type']; + $reverseMethod = Util::toCamelCase( $foreignLink['params']['type'].'-'.$currentType ); } $method = Util::toCamelCase($method); - /*if ($method == 'belongsToParent') { + //echo + /*if ($method == 'hasManyBelongsTo' || $reverseMethod == 'belongshasManyBelongsToTo') { die($entityName.' - '.$linkName); }*/ - if (method_exists($this->getLinkConverter(), $method)) { - $convertedLink = $this->getLinkConverter()->process($method, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink); - //print_r($convertedLink); + if (method_exists($this->getLinks(), $method)) { //ex. hasManyHasMany + $convertedLink = $this->getLinks()->process($method, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink); + } else if (method_exists($this->getLinks(), $currentType)) { //ex. hasMany + $convertedLink = $this->getLinks()->process($currentType, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink); } + /*else if (isset($reverseMethod) && method_exists($this->getLinks(), $reverseMethod)) { + $convertedLink = $this->getLinks()->process($reverseMethod, $entityName, $foreignLink, array('name'=>$linkName, 'params'=>$linkParams)); + } */ + + //$relationships = Util::merge($relationships, $convertedLink); + $relationships = Util::merge($convertedLink, $relationships); + //echo $method.' = '.$currentType.' - '.$foreignLink['type'].'
'; - - } - return $convertedMeta; + return $relationships; } @@ -329,8 +294,4 @@ class Base return $values; } - -} - - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Converters/Schema.php b/application/Espo/Core/Utils/Database/Converters/Schema.php new file mode 100644 index 0000000000..77d2e46a03 --- /dev/null +++ b/application/Espo/Core/Utils/Database/Converters/Schema.php @@ -0,0 +1,112 @@ + 'varchar', + 'len' => '24', + ); + + //pair espo::doctrine + protected $allowedDbFieldParams = array( + 'len' => 'length', + 'default' => 'default', + ); + + public function __construct() + { + $this->dbalSchema = new \Doctrine\DBAL\Schema\Schema(); + + $this->typeList = array_keys(\Doctrine\DBAL\Types\Type::getTypesMap()); + } + + protected function getDbalSchema() + { + return $this->dbalSchema; + } + + + + //convertToSchema + public function process(array $databaseMeta, $entityDefs) + { + $schema = $this->getDbalSchema(); + + $tables = array(); + foreach ($databaseMeta as $entityName => $entityParams) { + + $tables[$entityName] = $schema->createTable( Util::toUnderScore($entityName) ); + + $primaryColumns = array(); + foreach ($entityParams['fields'] as $fieldName => $fieldParams) { + + if (isset($fieldParams['notStorable']) && $fieldParams['notStorable']) { + continue; + } + + if ($fieldParams['type'] == 'id') { + $primaryColumns[] = Util::toUnderScore($fieldName); + } + + switch ($fieldParams['type']) { + case 'id': + $primaryColumns[] = Util::toUnderScore($fieldName); + + case 'id': + case 'foreignId': + $fieldParams = $this->idParams; + break; + + case 'array': + case 'json_array': + $fieldParams['default'] = ''; //for db type TEXT can't be defined a default value + break; + } + + if (!in_array($fieldParams['type'], $this->typeList)) { + $GLOBALS['log']->add('DEBUG', 'Field type ['.$fieldParams['type'].'] does not exist '.$entityName.':'.$fieldName); + continue; + } + + //echo Util::toUnderScore($fieldName).', '.$fieldParams['type'].', '.print_r($this->getDbFieldParams($fieldParams),1).'
'; + + $tables[$entityName]->addColumn(Util::toUnderScore($fieldName), $fieldParams['type'], $this->getDbFieldParams($fieldParams)); + } + + $tables[$entityName]->setPrimaryKey($primaryColumns); + } + + /* foreach ($databaseMeta as $entityName => $entityParams) { + + foreach ($databaseMeta['relations'] as $relationName => $relationParams) { + $myForeign->addForeignKeyConstraint($myTable, array("user_id"), array("id"), array("onUpdate" => "CASCADE")); + } + }*/ + + return $schema; + } + + + protected function getDbFieldParams($fieldParams) + { + $dbFieldParams = array(); + + foreach($this->allowedDbFieldParams as $espoName => $dbalName) { + + if (isset($fieldParams[$espoName])) { + $dbFieldParams[$dbalName] = $fieldParams[$espoName]; + } + } + + return $dbFieldParams; + } +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/FieldTypes/Bool.php b/application/Espo/Core/Utils/Database/FieldTypes/Bool.php new file mode 100644 index 0000000000..a9f68cd502 --- /dev/null +++ b/application/Espo/Core/Utils/Database/FieldTypes/Bool.php @@ -0,0 +1,45 @@ +getBooleanTypeDeclarationSQL($fieldDeclaration); + } + + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return $platform->convertBooleans($value); + } + + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (bool) $value; + } + + public function getBindingType() + { + return \PDO::PARAM_BOOL; + } +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/FieldTypes/Int.php b/application/Espo/Core/Utils/Database/FieldTypes/Int.php new file mode 100644 index 0000000000..f328b3637c --- /dev/null +++ b/application/Espo/Core/Utils/Database/FieldTypes/Int.php @@ -0,0 +1,35 @@ +getIntegerTypeDeclarationSQL($fieldDeclaration); + } + + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (int) $value; + } + + + public function getBindingType() + { + return \PDO::PARAM_INT; + } +} \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/Types/Password.php b/application/Espo/Core/Utils/Database/FieldTypes/Password.php similarity index 88% rename from application/Espo/Core/Doctrine/Types/Password.php rename to application/Espo/Core/Utils/Database/FieldTypes/Password.php index e85b4c39f1..b9bf67d5b1 100644 --- a/application/Espo/Core/Doctrine/Types/Password.php +++ b/application/Espo/Core/Utils/Database/FieldTypes/Password.php @@ -1,5 +1,6 @@ getVarcharTypeDeclarationSQL($fieldDeclaration); @@ -24,9 +30,6 @@ class Password extends Type return $value; } */ - public function getName() - { - return self::PASSWORD; - } + } diff --git a/application/Espo/Core/Utils/Database/FieldTypes/Varchar.php b/application/Espo/Core/Utils/Database/FieldTypes/Varchar.php new file mode 100644 index 0000000000..c0fd317834 --- /dev/null +++ b/application/Espo/Core/Utils/Database/FieldTypes/Varchar.php @@ -0,0 +1,29 @@ +getVarcharTypeDeclarationSQL($fieldDeclaration); + //return 'varchar'; + } + + + public function getDefaultLength(AbstractPlatform $platform) + { + return $platform->getVarcharDefaultLength(); + } +} \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/Converter/Link.php b/application/Espo/Core/Utils/Database/Links.php similarity index 52% rename from application/Espo/Core/Doctrine/Converter/Link.php rename to application/Espo/Core/Utils/Database/Links.php index cbf0aae490..94f9544f2c 100644 --- a/application/Espo/Core/Doctrine/Converter/Link.php +++ b/application/Espo/Core/Utils/Database/Links.php @@ -1,21 +1,21 @@ metadata = $metadata; - $this->association = new \Espo\Core\Doctrine\Converter\Association(); + $this->relations = new \Espo\Core\Utils\Database\Relations(); } protected function getMetadata() @@ -23,9 +23,9 @@ class Link return $this->metadata; } - protected function getAssociation() + protected function getRelations() { - return $this->association; + return $this->relations; } @@ -34,46 +34,27 @@ class Link if (isset($link['params'])) { return isset($link['params']['entity']) ? $link['params']['entity'] : $entityName; } + /*if (!isset($link['entity']) && isset($link['entities'])) { + return $link['entities']; + } */ return isset($link['entity']) ? $link['entity'] : $entityName; } - public function toUnderScore($name) - { - return Util::fromCamelCase($name, '_'); - } - - protected function getJoinTable($tableName1, $tableName2) - { - $tables = array( - $this->toUnderScore($tableName1), - $this->toUnderScore($tableName2), - ); - - asort($tables); - - return implode('_', $tables); - } - public function process($method, $entityName, $link, $foreignLink = array()) { $params = array(); $params['entityName'] = $entityName; - $params['usEntityName'] = $this->toUnderScore($entityName); $params['link'] = $link; - $params['usLinkName'] = $this->toUnderScore($link['name']); $foreignParams = array(); $foreignParams['entityName'] = $this->getLinkEntityName($entityName, $link); - $foreignParams['usEntityName'] = $this->toUnderScore($foreignParams['entityName']); $foreignParams['link'] = $foreignLink; - $foreignParams['usLinkName'] = $this->toUnderScore($foreignParams['link']['name']); - - $params['targetEntity'] = $this->getMetadata()->getEntityPath($foreignParams['entityName']); - $foreignParams['targetEntity'] = $this->getMetadata()->getEntityPath($params['entityName']); - - $params['joinTable'] = $foreignParams['targetEntity'] = $this->getJoinTable($params['entityName'], $foreignParams['entityName']); + //$params['targetEntity'] = $this->getMetadata()->getEntityPath($foreignParams['entityName']); + //$foreignParams['targetEntity'] = $this->getMetadata()->getEntityPath($params['entityName']); + $params['targetEntity'] = $foreignParams['entityName']; + $foreignParams['targetEntity'] = $params['entityName']; if (method_exists($this, $method)) { return $this->$method($params, $foreignParams); @@ -86,49 +67,59 @@ class Link protected function belongsTo($params, $foreignParams) { - return $this->getAssociation()->manyToOneUnidirectional($params, $foreignParams); + return $this->getRelations()->belongsTo($params, $foreignParams); } - //TODO: hook for teams protected function hasMany($params, $foreignParams) { - return $this->getAssociation()->oneToManyUnidirectionalWithJoinTable($params, $foreignParams); + return $this->getRelations()->hasMany($params, $foreignParams); } protected function hasManyHasMany($params, $foreignParams) { - return $this->getAssociation()->manyToManyBidirectional($params, $foreignParams); + return $this->getRelations()->manyMany($params, $foreignParams); } - protected function hasOne($params, $foreignParams) - { - return $this->getAssociation()->oneToOneUnidirectional($params, $foreignParams); - } - protected function hasOneBelongsTo($params, $foreignParams) + protected function hasChildren($params, $foreignParams) { - return $this->getAssociation()->oneToOneBidirectional($params, $foreignParams); + return $this->getRelations()->hasChildren($params, $foreignParams); } protected function belongsToParent($params, $foreignParams) { - return $this->getAssociation()->oneToManySelfReferencing($params, $foreignParams); + return $this->getRelations()->belongsToParent($params, $foreignParams); } + /*protected function hasChildrenBelongsToParent() + { + return $this->getRelations()->hasChildren($params, $foreignParams); + }*/ + + /*protected function hasManyBelongsTo($params, $foreignParams) + { + $hasMany = $this->getRelations()->hasMany($params, $foreignParams); + $belongsTo = $this->getRelations()->belongsTo($foreignParams, $params); + //$belongsTo [Contact] [relations] [account] ['foreignKey'] = 'id'; ??? + + return Util::merge($hasMany, $belongsTo); + } */ + + /* - +[0] => belongsTo + [0] => belongsTo [1] => belongsToParent [2] => hasManyBelongsToParent - +[3] => hasMany + [3] => hasMany [4] => hasChildrenBelongsToParent - +[5] => hasOne - +[6] => hasManyHasMany + [5] => hasOne + [6] => hasManyHasMany [7] => hasManyBelongsTo [8] => hasChildrenHasMany [9] => hasChildren @@ -161,7 +152,6 @@ class Link [7] => hasManyHasMany [8] => hasManyBelongsTo [9] => hasChildrenHasMany - [10] => hasChildren [11] => belongsToHasMany [12] => joint */ diff --git a/application/Espo/Core/Utils/Database/Relations.php b/application/Espo/Core/Utils/Database/Relations.php new file mode 100644 index 0000000000..d91efd5497 --- /dev/null +++ b/application/Espo/Core/Utils/Database/Relations.php @@ -0,0 +1,179 @@ +getSortEntities($tableName1, $tableName2); + + return Util::toCamelCase( implode('-', $tables) ); + } + + + + + //todo sedine in foreign fieldDefs a key for current + public function manyMany($params, $foreignParams) + { + $sortedEntities = $this->getSortEntities($params['entityName'], $foreignParams['entityName']); + + $relation = array(); + if (strtolower($params['entityName']) == strtolower($sortedEntities[0])) { + $relation = array( + $params['entityName'] => array( + 'relations' => array( + $params['link']['name'] => array( + 'type' => Entity::MANY_MANY, + 'entity' => $params['targetEntity'], + 'relationName' => $this->getJoinTable($params['entityName'], $foreignParams['entityName']), + 'key' => 'id', //todo specify 'key' + 'foreignKey' => 'id', //todo specify 'foreignKey' + 'midKeys' => array( + $sortedEntities[0].'Id', + $sortedEntities[1].'Id', + ), + ), + ), + ), + ); + } + + return $relation; + } + + + public function hasMany($params, $foreignParams) + { + $relation = array( + $params['entityName'] => array ( + 'relations' => array( + $params['link']['name'] => array( + 'type' => Entity::HAS_MANY, + 'entity' => $params['targetEntity'], + 'foreignKey' => lcfirst($foreignParams['link']['name'].'Id'), //???: 'foreignKey' => $params['link']['name'].'Id', + ), + ), + ), + ); + + return $relation; + } + + public function belongsTo($params, $foreignParams) + { + $relation = array ( + $params['entityName'] => array ( + 'fields' => array( + $params['link']['name'].'Name' => array( + 'type' => Entity::FOREIGN, + 'relation' => $params['link']['name'], + 'notStorable' => true, + ), + $params['link']['name'].'Id' => array( + 'type' => Entity::FOREIGN_ID, + ), + ), + 'relations' => array( + $params['link']['name'] => array( + 'type' => Entity::BELONGS_TO, + 'entity' => $params['targetEntity'], + 'key' => $params['link']['name'].'Id', + 'foreignKey' => 'id', //???? + ), + ), + ), + ); + + if (isset($params['link']['foreign'])) { //??? + $relation[$params['entityName']] ['fields'] [$params['link']['name'].'Name'] ['foreign'] = $params['link']['foreign']; + } + + return $relation; + } + + public function hasChildren($params, $foreignParams) + { + $relation = array( + $params['entityName'] => array ( + 'relations' => array( + $params['link']['name'] => array( + 'type' => Entity::HAS_CHILDREN, + 'entity' => $params['targetEntity'], + 'foreignKey' => $foreignParams['link']['name'].'Id', //???: 'foreignKey' => $params['link']['name'].'Id', + 'foreignType' => $foreignParams['link']['name'].'Type', //???: 'foreignKey' => $params['link']['name'].'Id', + ), + ), + ), + + /*$foreignParams['entityName'] => array ( + 'fields' => array( + $foreignParams['link']['name'].'Id' => array( + 'type' => Entity::FOREIGN_ID, + ), + $foreignParams['link']['name'].'Type' => array( + 'type' => Entity::FOREIGN_TYPE, + ), + $foreignParams['link']['name'].'Name' => array( + 'type' => Entity::VARCHAR, + 'notStorable' => true, + ), + ), + ), */ + ); + + + return $relation; + } + + public function belongsToParent($params, $foreignParams) + { + $relation = array(); + + $entities = isset($params['link']['params']['entities']) ? $params['link']['params']['entities'] : array($params['entityName']); + + foreach($entities as $entity) { + $relation[$entity] = array ( + 'fields' => array( + $params['link']['name'].'Id' => array( + 'type' => Entity::FOREIGN_ID, + ), + $params['link']['name'].'Type' => array( + 'type' => Entity::FOREIGN_TYPE, + ), + $params['link']['name'].'Name' => array( + 'type' => Entity::VARCHAR, + 'notStorable' => true, + ), + ), + ); + } + + return $relation; + } + + + public function hasOne($params, $foreignParams) + { + + } + + +} \ No newline at end of file diff --git a/application/Espo/Core/Utils/Database/Schema.php b/application/Espo/Core/Utils/Database/Schema.php new file mode 100644 index 0000000000..95cce5bf61 --- /dev/null +++ b/application/Espo/Core/Utils/Database/Schema.php @@ -0,0 +1,182 @@ +config = $config; + $this->metadata = $metadata; + $this->fileManager = $fileManager; + + $this->comparator = new \Doctrine\DBAL\Schema\Comparator(); + $this->initFieldTypes(); + + $this->converter = new \Espo\Core\Utils\Database\Converter($this->metadata); + } + + + protected function getConfig() + { + return $this->config; + } + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getFileManager() + { + return $this->fileManager; + } + + protected function getComparator() + { + return $this->comparator; + } + + protected function getConverter() + { + return $this->converter; + } + + public function getPlatform() + { + return $this->getConnection()->getDatabasePlatform(); + } + + + public function getConnection() + { + if (isset($this->connection)) { + return $this->connection; + } + + $dbalConfig = new \Doctrine\DBAL\Configuration(); + + $connectionParams = (array) $this->getConfig()->get('database'); + + $this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $dbalConfig); + + return $this->connection; + } + + + protected function initFieldTypes() + { + $typePaths = array( + 'Espo/Core/Utils/Database/FieldTypes', + 'Espo/Custom/Core/Utils/Database/FieldTypes', + ); + + foreach($typePaths as $path) { + + $typeList = $this->getFileManager()->getFileList('application/'.$path, false, '\.php$'); + if ($typeList !== false) { + foreach($typeList as $name) { + $typeName = preg_replace('/\.php$/i', '', $name); + $dbalTypeName = strtolower($typeName); + $class = \Espo\Core\Utils\Util::toFormat($path, '\\').'\\'.$typeName; + + if( ! Type::hasType($dbalTypeName) ) { + Type::addType($dbalTypeName, $class); + } else { + Type::overrideType($dbalTypeName, $class); + } + + $dbTypeName = method_exists($class, 'getDbTypeName') ? $class::getDbTypeName() : $dbalTypeName; + + $this->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping($dbTypeName, $dbalTypeName); + } + } + } + } + + + + /* + * Rebuild database schema + */ + public function rebuild() + { + if ($this->getConverter()->process() === false) { + return false; + } + + $currentSchema = $this->getCurrentSchema(); + $metadataSchema = $this->getConverter()->getSchemaFromMetadata(); + + $queries = $this->getDiffSql($currentSchema, $metadataSchema); + + $result = true; + $connection = $this->getConnection(); + foreach ($queries as $sql) { + try { + $result &= (bool) $connection->executeQuery($sql); + } catch (\Exception $e) { + $GLOBALS['log']->add('EXCEPTION', 'Rebuild database fault: '.$e); + } + } + + return $result; + } + + + + /* + * Get current database schema + * + * @return \Doctrine\DBAL\Schema\Schema + */ + protected function getCurrentSchema() + { + return $this->getConnection()->getSchemaManager()->createSchema(); + } + + /* + * Get SQL queries of database schema + * + * @params \Doctrine\DBAL\Schema\Schema $schema + * + * @return array - array of SQL queries + */ + public function toSql(\Doctrine\DBAL\Schema\SchemaDiff $schema) //Doctrine\DBAL\Schema\SchemaDiff | \Doctrine\DBAL\Schema\Schema + { + return $schema->toSaveSql($this->getPlatform()); + //return $schema->toSql($this->getPlatform()); //it can return with DROP TABLE + } + + + /* + * Get SQL queries to get from one to another schema + * + * @return array - array of SQL queries + */ + public function getDiffSql(\Doctrine\DBAL\Schema\Schema $fromSchema, \Doctrine\DBAL\Schema\Schema $toSchema) + { + $schemaDiff = $this->getComparator()->compare($fromSchema, $toSchema); + + return $this->toSql($schemaDiff); //$schemaDiff->toSql($this->getPlatform()); + } + + + + +} diff --git a/application/Espo/Core/Utils/File/Manager.php b/application/Espo/Core/Utils/File/Manager.php index fd38c7131d..859195b9dd 100644 --- a/application/Espo/Core/Utils/File/Manager.php +++ b/application/Espo/Core/Utils/File/Manager.php @@ -44,6 +44,10 @@ class Manager */ function getFileList($path, $recursively=false, $filter='', $fileType='all') { + if (!file_exists($path)) { + return false; + } + $result = array(); $cdir = scandir($path); diff --git a/application/Espo/Core/Utils/Metadata.php b/application/Espo/Core/Utils/Metadata.php index 7e7631fea4..a20637ba52 100644 --- a/application/Espo/Core/Utils/Metadata.php +++ b/application/Espo/Core/Utils/Metadata.php @@ -2,15 +2,14 @@ namespace Espo\Core\Utils; -use Doctrine\ORM\Tools; - class Metadata { protected $metadataConfig; - protected $doctrineMetadataName = 'defs'; //Metadata "defs" uses for creating the metadata of Doctri protected $meta; + private $espoMetadata; + protected $scopes= array(); private $config; @@ -189,19 +188,35 @@ class Metadata $result= $this->getFileManager()->setContent($data, $fullPath, $scope.'.json'); - //create classes only for "defs" metadata - /*if ($type == $this->getMetaConfig()->espoMetadataName) { - try{ - $this->getDoctrineConverter()->generateEntities( array($this->getEntityPath($scope)) ); - } catch (\Exception $e) { - $GLOBALS['log']->add('EXCEPTION', 'Try to generate Entities for '.$this->getEntityPath($scope).'. Details: '.$e->getMessage()); - } - }*/ - return $result; } + public function getEspoMetadata() + { + if (!empty($this->espoMetadata)) { + return $this->espoMetadata; + } + + $this->espoMetadata = $this->getFileManager()->getContent($this->getMetaConfig()->cachePath, 'espoMetadata.php'); + + return $this->espoMetadata; + } + + public function setEspoMetadata(array $espoMetadata) + { + $result = $this->getFileManager()->setContentPHP($espoMetadata, $this->getMetaConfig()->cachePath, 'espoMetadata.php'); + if ($result == false) { + $GLOBALS['log']->add('EXCEPTION', 'Metadata::setEspoMetadata() - Cannot save espoMetadata to a file'); + throw new \Espo\Core\Exceptions\Error(); + } + + $this->espoMetadata = $espoMetadata; + + return $result; + } + + /** * Unite file content to the file * diff --git a/application/Espo/Core/Utils/Util.php b/application/Espo/Core/Utils/Util.php index 909bfea312..83c9ab7d66 100644 --- a/application/Espo/Core/Utils/Util.php +++ b/application/Espo/Core/Utils/Util.php @@ -73,6 +73,19 @@ class Util return preg_replace_callback('/([A-Z])/', $func, $name); } + /** + * Convert name from Camel Case format to underscore. + * ex. camelCase to camel_case + * + * @param string $name + * + * @return string + */ + public static function toUnderScore($name) + { + return static::fromCamelCase($name, '_'); + } + /** * Merge arrays (default PHP function is not suitable) diff --git a/application/Espo/Core/defaults/systemConfig.php b/application/Espo/Core/defaults/systemConfig.php index 801076def3..44a9d2ea49 100644 --- a/application/Espo/Core/defaults/systemConfig.php +++ b/application/Espo/Core/defaults/systemConfig.php @@ -20,8 +20,6 @@ return array ( 'cachePath' => 'data/cache/application', 'corePath' => 'application/Espo/Resources/metadata', 'customPath' => 'application/Espo/Modules/{*}/Resources/metadata', - 'doctrineCache' => 'data/cache/doctrine/metadata', - 'espoMetadataName' => 'entityDefs', ), 'layoutConfig' => diff --git a/application/Espo/Entities/Bug.php b/application/Espo/Entities/Bug.php deleted file mode 100644 index c7be91de44..0000000000 --- a/application/Espo/Entities/Bug.php +++ /dev/null @@ -1,122 +0,0 @@ -products = new ArrayCollection(); - } - - public function getId() - { - return $this->id; - } - - public function getDescription() - { - return $this->description; - } - - public function setDescription($description) - { - $this->description = $description; - } - - public function setCreated(DateTime $created) - { - $this->created = $created; - } - - public function getCreated() - { - return $this->created; - } - - public function setStatus($status) - { - $this->status = $status; - } - - public function getStatus() - { - return $this->status; - } - - public function setEngineer($engineer) - { - $engineer->assignedToBug($this); - $this->engineer = $engineer; - } - - public function setReporter($reporter) - { - $reporter->addReportedBug($this); - $this->reporter = $reporter; - } - - public function getEngineer() - { - return $this->engineer; - } - - public function getReporter() - { - return $this->reporter; - } - - public function assignToProduct($product) - { - $this->products[] = $product; - } - - public function getProducts() - { - return $this->products; - } - - public function close() - { - $this->status = "CLOSE"; - } -} - - diff --git a/application/Espo/Entities/BugRepository.php b/application/Espo/Entities/BugRepository.php deleted file mode 100644 index 1e1daf5e2e..0000000000 --- a/application/Espo/Entities/BugRepository.php +++ /dev/null @@ -1,47 +0,0 @@ -getEntityManager()->createQuery($dql); - $query->setMaxResults($number); - return $query->getResult(); - } - - public function getRecentBugsArray($number = 30) - { - $dql = "SELECT b, e, r, p FROM Bug b JOIN b.engineer e ". - "JOIN b.reporter r JOIN b.products p ORDER BY b.created DESC"; - $query = $this->getEntityManager()->createQuery($dql); - $query->setMaxResults($number); - return $query->getArrayResult(); - } - - public function getUsersBugs($userId, $number = 15) - { - $dql = "SELECT b, e, r FROM Bug b JOIN b.engineer e JOIN b.reporter r ". - "WHERE b.status = 'OPEN' AND e.id = ?1 OR r.id = ?1 ORDER BY b.created DESC"; - - return $this->getEntityManager()->createQuery($dql) - ->setParameter(1, $userId) - ->setMaxResults($number) - ->getResult(); - } - - public function getOpenBugsByProduct() - { - $dql = "SELECT p.id, p.name, count(b.id) AS openBugs FROM Bug b ". - "JOIN b.products p WHERE b.status = 'OPEN' GROUP BY p.id"; - return $this->getEntityManager()->createQuery($dql)->getScalarResult(); - } -} diff --git a/application/Espo/Entities/User.php b/application/Espo/Entities/User.php index 9e6d92c2b6..2db29c3067 100644 --- a/application/Espo/Entities/User.php +++ b/application/Espo/Entities/User.php @@ -2,15 +2,11 @@ namespace Espo\Entities; -use Doctrine\Common\Collections\ArrayCollection; - -/** - * @Entity @Table(name="users") - */ class User extends \Espo\ORM\Entity { public function isAdmin() { return $this->get('isAdmin'); - } + } + } diff --git a/application/Espo/Modules/Crm/Resources/metadata/defs/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/defs/Contact.json deleted file mode 100644 index 1bee489fcc..0000000000 --- a/application/Espo/Modules/Crm/Resources/metadata/defs/Contact.json +++ /dev/null @@ -1 +0,0 @@ -{"module":"Test","var1":{"subvar1":"NEWsubval1","subvar55":"subval55"}} \ No newline at end of file diff --git a/application/Espo/Modules/Crm/Resources/metadata/defs/Product.json b/application/Espo/Modules/Crm/Resources/metadata/defs/Product.json deleted file mode 100644 index 500d240666..0000000000 --- a/application/Espo/Modules/Crm/Resources/metadata/defs/Product.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "table":"products", - "type":"entity", - "id":{ - "id":{ - "type":"string", - "generator":{ - "strategy":"UUID" - } - } - }, - "fields":{ - "name":{ - "type":"string" - } - } -} diff --git a/application/Espo/Modules/Crm/Resources/metadata/defs/unset.json b/application/Espo/Modules/Crm/Resources/metadata/defs/unset.json deleted file mode 100644 index 3f95c8cc5c..0000000000 --- a/application/Espo/Modules/Crm/Resources/metadata/defs/unset.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "Crm.Test": [ - "var1.subvar2" - ] -} \ No newline at end of file diff --git a/application/Espo/ORM/EntityFactory.php b/application/Espo/ORM/EntityFactory.php index 3b2a4ca852..18eab322af 100644 --- a/application/Espo/ORM/EntityFactory.php +++ b/application/Espo/ORM/EntityFactory.php @@ -1,26 +1,26 @@ -entityManager = $entityManager; - $this->metadata = $metadata; - } - public function create($name) - { - $className = $this->entityManager->normalizeEntityName($name); - $defs = $this->metdata->get($name); - $entity = new $className($defs); - return $entity; - } - -} - - +entityManager = $entityManager; + $this->metadata = $metadata; + } + public function create($name) + { + $className = $this->entityManager->normalizeEntityName($name); + $defs = $this->metadata->get($name); + $entity = new $className($defs); + return $entity; + } + +} + + diff --git a/application/Espo/ORM/EntityManager.php b/application/Espo/ORM/EntityManager.php index ba7c138f4a..0bd4a98970 100644 --- a/application/Espo/ORM/EntityManager.php +++ b/application/Espo/ORM/EntityManager.php @@ -37,7 +37,7 @@ class EntityManager if (!empty($params['mapperClassName'])) { $mapperClassName = $params['mapperClassName']; } - $this->mapper = new $mapperClassName($pdo, $this->entityFactory); + $this->mapper = new $mapperClassName($this->pdo, $this->entityFactory); $repositoryFactoryClassName = '\\Espo\\ORM\\RepositoryFactory'; if (!empty($params['repositoryFactoryClassName'])) { diff --git a/application/Espo/Resources/metadata/defs/Bug.json b/application/Espo/Resources/metadata/defs/Bug.json deleted file mode 100644 index b8f93aa5b2..0000000000 --- a/application/Espo/Resources/metadata/defs/Bug.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "type":"entity", - "manyToOne":{ - "reporter":{ - "inversedBy":"reportedBugs", - "targetEntity":"Espo\\Entities\\User" - }, - "engineer":{ - "inversedBy":"assignedBugs", - "targetEntity":"Espo\\Entities\\User" - } - }, - "fields":{ - "status":{ - "type":"string" - }, - "description":{ - "type":"text" - }, - "created":{ - "type":"datetime" - } - }, - "repositoryClass":"BugRepository", - "table":"bugs", - "id":{ - "id":{ - "type":"string", - "generator":{ - "strategy":"UUID" - } - } - } -} - diff --git a/application/Espo/Resources/metadata/defs/User.json b/application/Espo/Resources/metadata/defs/User.json deleted file mode 100644 index e99475ea65..0000000000 --- a/application/Espo/Resources/metadata/defs/User.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "table":"users", - "type":"entity", - "id":{ - "id":{ - "type":"string", - "generator":{ - "strategy":"UUID" - } - } - }, - "fields":{ - "username":{ - "type":"string(30)" - }, - "password":{ - "type":"string(255)" - }, - "isAdmin":{ - "type":"boolean", - "options":{ - "default":0 - } - } - } -} diff --git a/application/Espo/Resources/metadata/entityDefs/User.json b/application/Espo/Resources/metadata/entityDefs/User.json index 17b3e86137..77b5645d82 100644 --- a/application/Espo/Resources/metadata/entityDefs/User.json +++ b/application/Espo/Resources/metadata/entityDefs/User.json @@ -10,6 +10,9 @@ }, "name": { "type": "personName" + }, + "password": { + "type": "password" }, "salutationName": { "type": "enum", diff --git a/application/Espo/Resources/metadata/fields/autoincrement.json b/application/Espo/Resources/metadata/fields/autoincrement.json index c32640cb6f..a9e95aefea 100644 --- a/application/Espo/Resources/metadata/fields/autoincrement.json +++ b/application/Espo/Resources/metadata/fields/autoincrement.json @@ -6,7 +6,7 @@ "advanced":true }, "database":{ - "type":"integer", + "type":"int", "autoincrement":true } } diff --git a/application/Espo/Resources/metadata/fields/base.json b/application/Espo/Resources/metadata/fields/base.json index b9b2a2858d..8b72ad6bcb 100644 --- a/application/Espo/Resources/metadata/fields/base.json +++ b/application/Espo/Resources/metadata/fields/base.json @@ -4,6 +4,6 @@ "advanced":false }, "database":{ - "db": false + "notStorable":true } } diff --git a/application/Espo/Resources/metadata/fields/bool.json b/application/Espo/Resources/metadata/fields/bool.json index 85dad49a48..5db27091c4 100644 --- a/application/Espo/Resources/metadata/fields/bool.json +++ b/application/Espo/Resources/metadata/fields/bool.json @@ -8,8 +8,5 @@ "search":{ "basic":false, "advanced":true - }, - "database":{ - "type":"boolean" } } diff --git a/application/Espo/Resources/metadata/fields/duration.json b/application/Espo/Resources/metadata/fields/duration.json index c936f61d65..d629720b67 100644 --- a/application/Espo/Resources/metadata/fields/duration.json +++ b/application/Espo/Resources/metadata/fields/duration.json @@ -1,5 +1,5 @@ -{ - "database":{ - "type":"integer" - } -} +{ + "database":{ + "type":"int" + } +} diff --git a/application/Espo/Resources/metadata/fields/email.json b/application/Espo/Resources/metadata/fields/email.json index e8e22e7401..2b4b87d9a0 100644 --- a/application/Espo/Resources/metadata/fields/email.json +++ b/application/Espo/Resources/metadata/fields/email.json @@ -15,6 +15,6 @@ "advanced":true }, "database":{ - "type":"string" + "type":"varchar" } } diff --git a/application/Espo/Resources/metadata/fields/enum.json b/application/Espo/Resources/metadata/fields/enum.json index cbd7aaa78a..37332b807c 100644 --- a/application/Espo/Resources/metadata/fields/enum.json +++ b/application/Espo/Resources/metadata/fields/enum.json @@ -23,6 +23,6 @@ "advanced":true }, "database":{ - "type":"string" + "type":"varchar" } } diff --git a/application/Espo/Resources/metadata/fields/enumInt.json b/application/Espo/Resources/metadata/fields/enumInt.json index f9b91b256c..c7c767d225 100644 --- a/application/Espo/Resources/metadata/fields/enumInt.json +++ b/application/Espo/Resources/metadata/fields/enumInt.json @@ -18,6 +18,6 @@ "advanced":true }, "database":{ - "type":"integer" + "type":"int" } } diff --git a/application/Espo/Resources/metadata/fields/int.json b/application/Espo/Resources/metadata/fields/int.json index bd79f32114..79bd06eab6 100644 --- a/application/Espo/Resources/metadata/fields/int.json +++ b/application/Espo/Resources/metadata/fields/int.json @@ -21,8 +21,5 @@ "search":{ "basic":false, "advanced":true - }, - "database":{ - "type":"integer" } } diff --git a/application/Espo/Resources/metadata/fields/link.json b/application/Espo/Resources/metadata/fields/link.json index 748e20d4d3..7d151fa889 100644 --- a/application/Espo/Resources/metadata/fields/link.json +++ b/application/Espo/Resources/metadata/fields/link.json @@ -15,5 +15,8 @@ "search":{ "basic":false, "advanced":true + }, + "database":{ + "notStorable":true } } diff --git a/application/Espo/Resources/metadata/fields/linkMultiple.json b/application/Espo/Resources/metadata/fields/linkMultiple.json index 3cb9606194..e2ba43736b 100644 --- a/application/Espo/Resources/metadata/fields/linkMultiple.json +++ b/application/Espo/Resources/metadata/fields/linkMultiple.json @@ -15,5 +15,8 @@ "search":{ "basic":false, "advanced":true + }, + "database":{ + "notStorable":true } } diff --git a/application/Espo/Resources/metadata/fields/linkParent.json b/application/Espo/Resources/metadata/fields/linkParent.json index 23a9c3bc6c..5940f58c1d 100644 --- a/application/Espo/Resources/metadata/fields/linkParent.json +++ b/application/Espo/Resources/metadata/fields/linkParent.json @@ -16,5 +16,8 @@ "search":{ "basic":false, "advanced":true + }, + "database":{ + "notStorable":true } } diff --git a/application/Espo/Resources/metadata/fields/multienum.json b/application/Espo/Resources/metadata/fields/multienum.json index e10385bf47..a98f0c50a0 100644 --- a/application/Espo/Resources/metadata/fields/multienum.json +++ b/application/Espo/Resources/metadata/fields/multienum.json @@ -17,8 +17,5 @@ "search":{ "basic":false, "advanced":false - }, - "database":{ - "type":"json_array" } } diff --git a/application/Espo/Resources/metadata/fields/phone.json b/application/Espo/Resources/metadata/fields/phone.json index d4e3bb2404..d7e2242c17 100644 --- a/application/Espo/Resources/metadata/fields/phone.json +++ b/application/Espo/Resources/metadata/fields/phone.json @@ -20,6 +20,6 @@ "advanced":true }, "database":{ - "type":"string" + "type":"varchar" } } diff --git a/application/Espo/Resources/metadata/fields/url.json b/application/Espo/Resources/metadata/fields/url.json index 6b4282ec99..ee2c542225 100644 --- a/application/Espo/Resources/metadata/fields/url.json +++ b/application/Espo/Resources/metadata/fields/url.json @@ -19,6 +19,6 @@ "advanced":true }, "database":{ - "type":"string" + "type":"varchar" } } diff --git a/application/Espo/Resources/metadata/fields/varchar.json b/application/Espo/Resources/metadata/fields/varchar.json index 6b4282ec99..8bf30f983a 100644 --- a/application/Espo/Resources/metadata/fields/varchar.json +++ b/application/Espo/Resources/metadata/fields/varchar.json @@ -17,8 +17,5 @@ "search":{ "basic":true, "advanced":true - }, - "database":{ - "type":"string" } } diff --git a/testAuth.php b/testAuth.php index 15e8a25ceb..452cb5cd10 100644 --- a/testAuth.php +++ b/testAuth.php @@ -11,7 +11,7 @@ class Auth extends \Slim\Middleware private $container; - public function __construct(\Espo\Core\EntityManager $entityManager, \Espo\Core\Container $container) + public function __construct($entityManager, $container) { $this->entityManager = $entityManager; $this->container = $container; @@ -33,7 +33,7 @@ class Auth extends \Slim\Middleware if (!empty($routes[0])) { $routeConditions = $routes[0]->getConditions(); if (isset($routeConditions['auth']) && $routeConditions['auth'] === false) { - $this->container->setUser(new \Espo\Entities\User()); + //$this->container->setUser(new \Espo\Entities\User()); $this->next->call(); return; } @@ -49,13 +49,15 @@ class Auth extends \Slim\Middleware $username = $authKey; $password = $authSec; - $user = $this->entityManager->getRepository('User')->findOneBy(array('username' => $username)); + /*$user = $this->entityManager->getRepository('User')->findOneBy(array('username' => $username)); if ($user) { if ($password == $user->getPassword()) { $this->container->setUser($user); $isAuthenticated = true; } - } + } */ + + $isAuthenticated = true; if ($isAuthenticated) { $this->next->call(); diff --git a/tests/Espo/Core/Doctrine/EspoConverterTest.php b/tests/Espo/Core/Doctrine/EspoConverterTest.php deleted file mode 100644 index 9cad46854d..0000000000 --- a/tests/Espo/Core/Doctrine/EspoConverterTest.php +++ /dev/null @@ -1,45 +0,0 @@ -app = $GLOBALS['app']; - } - - - protected function setUp() - { - $this->fixture = new \Espo\Core\Doctrine\EspoConverter($this->app->getContainer()->get('entityManager'), $this->app->getMetadata(), $this->app->getContainer()->get('fileManager')); - } - - protected function tearDown() - { - $this->fixture = NULL; - } - - - - function testGetFieldType() - { - $this->assertEquals('string', $this->fixture->getFieldType('varchar')); - $this->assertEquals('float', $this->fixture->getFieldType('float')); - } - - - - -} - -?> \ No newline at end of file diff --git a/tests/Espo/Core/Utils/Database/RelationsTest.php b/tests/Espo/Core/Utils/Database/RelationsTest.php new file mode 100644 index 0000000000..eae7a15295 --- /dev/null +++ b/tests/Espo/Core/Utils/Database/RelationsTest.php @@ -0,0 +1,477 @@ +app = $GLOBALS['app']; + } + + + protected function setUp() + { + $this->object = new \Espo\Core\Utils\Database\Relations(); + } + + protected function tearDown() + { + $this->object = NULL; + } + + + public function invokeMethod($methodName, array $parameters = array()) + { + $reflection = new \ReflectionClass(get_class($this->object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($this->object, $parameters); + } + //$this->invokeMethod('cryptPassword', array('passwordToCrypt')); + + + + function testGetSortEntities() + { + $input = array( + 'entity1' => 'ContactTest', + 'entity2' => 'CallTest', + ); + + $result = array( + 0 => 'callTest', + 1 => 'contactTest', + ); + + $this->assertEquals($result, $this->invokeMethod('getSortEntities', array($input['entity1'], $input['entity2']))); + } + + + function testGetJoinTable() + { + $input = array( + 'entity1' => 'ContactTest', + 'entity2' => 'CallTest', + ); + + $result = 'callTestContactTest'; + + $this->assertEquals( $result, $this->invokeMethod('getJoinTable', array($input['entity1'], $input['entity2'])) ); + } + + + function testManyMany() + { + $input = array( + 'params' => array ( + 'entityName' => 'Call', + 'link' => + array ( + 'name' => 'contacts', + 'params' => + array ( + 'type' => 'hasMany', + 'entity' => 'Contact', + 'foreign' => 'calls', + ), + ), + 'targetEntity' => 'Contact', + ), + + + 'foreignParams' => array ( + 'entityName' => 'Contact', + 'link' => + array ( + 'name' => 'calls', + 'params' => + array ( + 'type' => 'hasMany', + 'entity' => 'Call', + 'foreign' => 'contacts', + ), + ), + 'targetEntity' => 'Call', + ), + ); + + $result = array( + 'Call' => + array ( + 'relations' => + array ( + 'contacts' => + array ( + 'type' => 'manyMany', + 'entity' => 'Contact', + 'relationName' => 'callContact', + 'key' => 'id', + 'foreignKey' => 'id', + 'midKeys' => + array ( + 'callId', + 'contactId', + ), + ), + ), + ), + ); + + + $this->assertEquals( $result, $this->invokeMethod('manyMany', array($input['params'], $input['foreignParams'])) ); + + //test reverse: result should be an empty array + $result = array(); + $this->assertEquals( $result, $this->invokeMethod('manyMany', array($input['foreignParams'], $input['params'])) ); + } + + + function testHasMany() + { + $input = array( + 'params' => array ( + 'entityName' => 'Account', + 'link' => + array ( + 'name' => 'contacts', + 'params' => + array ( + 'type' => 'hasMany', + 'entity' => 'Contact', + 'foreign' => 'account', + ), + ), + 'targetEntity' => 'Contact', + ), + + 'foreignParams' => array ( + 'entityName' => 'Contact', + 'link' => + array ( + 'name' => 'account', + 'params' => + array ( + 'type' => 'belongsTo', + 'entity' => 'Account', + ), + ), + 'targetEntity' => 'Account', + ), + ); + + $result = array ( + 'Account' => + array ( + 'relations' => + array ( + 'contacts' => + array ( + 'type' => 'hasMany', + 'entity' => 'Contact', + 'foreignKey' => 'accountId', + ), + ), + ), + ); + + + $this->assertEquals( $result, $this->invokeMethod('hasMany', array($input['params'], $input['foreignParams'])) ); + } + + + function testBelongsTo() + { + $input = array( + 'params' => array ( + 'entityName' => 'Attachment', + 'link' => + array ( + 'name' => 'createdBy', + 'params' => + array ( + 'type' => 'belongsTo', + 'entity' => 'User', + ), + ), + 'targetEntity' => 'User', + ), + + 'foreignParams' => array ( + 'entityName' => 'User', + 'link' => false, + 'targetEntity' => 'Attachment', + ), + ); + + $result = array ( + 'Attachment' => + array ( + 'fields' => + array ( + 'createdByName' => + array ( + 'type' => 'foreign', + 'relation' => 'createdBy', + 'notStorable' => true, + ), + 'createdById' => + array ( + 'type' => 'foreignId', + ), + ), + 'relations' => + array ( + 'createdBy' => + array ( + 'type' => 'belongsTo', + 'entity' => 'User', + 'key' => 'createdById', + 'foreignKey' => 'id', + ), + ), + ), + ); + + + $this->assertEquals( $result, $this->invokeMethod('belongsTo', array($input['params'], $input['foreignParams'])) ); + } + + + function testHasChildren() + { + $input = array( + 'params' => array ( + 'entityName' => 'Post', + 'link' => + array ( + 'name' => 'notes', + 'params' => + array ( + "type" => "hasChildren", + "entity" => "Post", + "foreign" => "parent", + ), + ), + 'targetEntity' => 'Note', + ), + + 'foreignParams' => array ( + 'entityName' => 'Note', + 'link' => array ( + 'name' => 'parent', + 'params' => + array ( + "type" => "belongsToParent", + "entities" => array("Post", "Account", "Case"), + "foreign" => "notes" + ), + ), + 'targetEntity' => 'Post', + ), + ); + + $result = array ( + 'Post' => + array ( + 'relations' => + array ( + 'notes' => + array ( + 'type' => 'hasChildren', + 'entity' => 'Note', + 'foreignKey' => 'parentId', + 'foreignType' => 'parentType', + ), + ), + ), + + /*'Note' => array( + 'fields' => array( + 'parentId' => array( + 'type' => 'foreignId', + ), + 'parentType' => array( + 'type' => 'foreignType', + ), + 'parentName' => array( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ),*/ + ); + + + $this->assertEquals( $result, $this->invokeMethod('hasChildren', array($input['params'], $input['foreignParams'])) ); + } + + + function testBelongsToParent_Single() + { + $input = array( + 'params' => array ( + 'entityName' => 'Note', + 'link' => + array ( + 'name' => 'parent', + 'params' => + array ( + 'type' => 'belongsToParent', + 'foreign' => 'notes', + ), + ), + 'targetEntity' => 'Note', + ), + + 'foreignParams' => array ( + 'entityName' => 'Note', + 'link' => + array ( + 'name' => 'attachments', + 'params' => + array ( + 'type' => 'hasChildren', + 'entity' => 'Attachment', + 'foreign' => 'parent', + ), + ), + 'targetEntity' => 'Note', + ), + ); + + $result = array ( + 'Note' => + array ( + 'fields' => + array ( + 'parentId' => + array ( + 'type' => 'foreignId', + ), + 'parentType' => + array ( + 'type' => 'foreignType', + ), + 'parentName' => + array ( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + ); + + $this->assertEquals( $result, $this->invokeMethod('belongsToParent', array($input['params'], $input['foreignParams'])) ); + } + + + function testBelongsToParent() + { + $input = array( + 'params' => array ( + 'entityName' => 'Call', + 'link' => + array ( + 'name' => 'parent', + 'params' => + array ( + 'type' => 'belongsToParent', + 'entities' => + array ( + 'Account', + 'Opportunity', + 'Case', + ), + 'foreign' => 'calls', + ), + ), + 'targetEntity' => 'Call', + ), + + 'foreignParams' => array ( + 'entityName' => 'Call', + 'link' => false, + 'targetEntity' => 'Call', + ), + ); + + $result = array ( + 'Account' => + array ( + 'fields' => + array ( + 'parentId' => + array ( + 'type' => 'foreignId', + ), + 'parentType' => + array ( + 'type' => 'foreignType', + ), + 'parentName' => + array ( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + 'Opportunity' => + array ( + 'fields' => + array ( + 'parentId' => + array ( + 'type' => 'foreignId', + ), + 'parentType' => + array ( + 'type' => 'foreignType', + ), + 'parentName' => + array ( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + 'Case' => + array ( + 'fields' => + array ( + 'parentId' => + array ( + 'type' => 'foreignId', + ), + 'parentType' => + array ( + 'type' => 'foreignType', + ), + 'parentName' => + array ( + 'type' => 'varchar', + 'notStorable' => true, + ), + ), + ), + ); + + $this->assertEquals( $result, $this->invokeMethod('belongsToParent', array($input['params'], $input['foreignParams'])) ); + } + + + + + + +} \ No newline at end of file