From 87418e6ffcdffc371e0996803baee176476cc6ba Mon Sep 17 00:00:00 2001 From: Taras Machyshyn Date: Thu, 5 Dec 2013 12:14:10 +0200 Subject: [PATCH] doctrine converter (unfinished) --- application/Espo/Core/Application.php | 6 +- .../Core/Doctrine/Converter/Association.php | 197 ++++++++++ .../Espo/Core/Doctrine/Converter/Base.php | 336 ++++++++++++++++++ .../Espo/Core/Doctrine/Converter/Link.php | 169 +++++++++ .../Espo/Core/Doctrine/EspoConverter.php | 327 ----------------- application/Espo/Core/Doctrine/Helper.php | 55 ++- application/Espo/Core/Utils/Util.php | 60 +++- .../Espo/Resources/metadata/fields/array.json | 3 + .../Resources/metadata/fields/duration.json | 5 + testAuth.php | 4 +- .../Espo/Core/Doctrine/EspoConverterTest.php | 45 +++ tests/Espo/Core/Utils/UtilTest.php | 32 ++ 12 files changed, 902 insertions(+), 337 deletions(-) create mode 100644 application/Espo/Core/Doctrine/Converter/Association.php create mode 100644 application/Espo/Core/Doctrine/Converter/Base.php create mode 100644 application/Espo/Core/Doctrine/Converter/Link.php delete mode 100644 application/Espo/Core/Doctrine/EspoConverter.php create mode 100644 application/Espo/Resources/metadata/fields/duration.json create mode 100644 tests/Espo/Core/Doctrine/EspoConverterTest.php diff --git a/application/Espo/Core/Application.php b/application/Espo/Core/Application.php index 900ea94590..4e26402246 100644 --- a/application/Espo/Core/Application.php +++ b/application/Espo/Core/Application.php @@ -79,11 +79,11 @@ class Application $this->getMetadata()->init($isNotCached); if ($isNotCached) { - $doctrineConverter = new \Espo\Core\Doctrine\EspoConverter($this->container->get('entityManager'), $this->getMetadata(), $this->container->get('fileManager')); + $doctrineConverter = new \Espo\Core\Doctrine\Converter\Base($this->container->get('entityManager'), $this->getMetadata(), $this->container->get('fileManager')); - if ($doctrineConverter->convertToDoctrine()) { + if ($doctrineConverter->process()) { try{ - $doctrineConverter->rebuildDatabase(); + $doctrineConverter->getDoctrineHelper()->rebuildDatabase(); } catch (\Exception $e) { $GLOBALS['log']->add('EXCEPTION', 'Fault to rebuildDatabase'.'. Details: '.$e->getMessage()); } diff --git a/application/Espo/Core/Doctrine/Converter/Association.php b/application/Espo/Core/Doctrine/Converter/Association.php new file mode 100644 index 0000000000..a4162eeea4 --- /dev/null +++ b/application/Espo/Core/Doctrine/Converter/Association.php @@ -0,0 +1,197 @@ + 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/Converter/Base.php b/application/Espo/Core/Doctrine/Converter/Base.php new file mode 100644 index 0000000000..b5a81e5f3e --- /dev/null +++ b/application/Espo/Core/Doctrine/Converter/Base.php @@ -0,0 +1,336 @@ + 'type', + 'maxLength' => 'length', + 'default' => array( + 'condition' => '^javascript:', + 'conditionEquals' => false, + 'value' => array( + 'options' => array ( + '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) + { + $this->entityManager = $entityManager; + $this->metadata = $metadata; + $this->fileManager = $fileManager; + + $this->doctrineHelper = new \Espo\Core\Doctrine\Helper($this->getEntityManager()->getWrapped()); + + $this->linkConverter = new \Espo\Core\Doctrine\Converter\Link($this->metadata); + } + + protected function getEntityManager() + { + return $this->entityManager; + } + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getFileManager() + { + return $this->fileManager; + } + + protected function getDoctrineHelper() + { + return $this->doctrineHelper; + } + + 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 + * + * @param string $entityName + * @param array $entityMeta + * + * @return array + */ + protected function convertFields($entityName, $entityMeta) + { + $outputMeta = array(); + foreach($entityMeta['fields'] as $fieldName => $fieldParams) { + + $fieldName = Util::fromCamelCase($fieldName, '_'); + + //check if "fields" option exists in $fieldMeta + $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, '_'), '_' ); + if (!isset($entityMeta['fields'][$subFieldNameNaming])) { + $subFieldDefs = $this->convertField($entityName, $subFieldName, $subFieldParams); + if ($subFieldDefs !== false) { + $outputMeta[$subFieldNameNaming] = $subFieldDefs; //push fieldDefs to the main array + } + } + + } + + } else { + $fieldDefs = $this->convertField($entityName, $fieldName, $fieldParams); + if ($fieldDefs !== false) { + $outputMeta[$fieldName] = $fieldDefs; //push fieldDefs to the main array + } + } + + + /*Make actions for different types like "link", "linkMultiple", "linkParent" */ + } + + return $outputMeta; + } + + + + /*It can be moved to separate file*/ + protected function convertField($entityName, $fieldName, array $fieldParams) + { + //set default type if exists + if (!isset($fieldParams['type']) || empty($fieldParams['type'])) { + $GLOBALS['log']->add('WARNING', 'Field type does not exist for '.$entityName.':'.$fieldName.'. Use default type ['.$this->defaultFieldType.']'); + $fieldParams['type'] = $this->defaultFieldType; + } //END: set default type if exists + + $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 + + $fieldDefs = $this->getInitValues($fieldParams); + + //merge database options from field definition + if (isset($fieldTypeMeta['database'])) { + $fieldDefs = Util::merge($fieldDefs, $fieldTypeMeta['database']); + } + + return $fieldDefs; + } + + + + protected function convertLinks($entityName, $entityMeta, array $entityDefs, array $convertedMeta) + { + if (!isset($entityMeta['links'])) { + return array(); + } + + foreach($entityMeta['links'] as $linkName => $linkParams) { + //echo $linkName.'
'; + //print_r($linkParams); + + $linkEntityName = $this->getLinkConverter()->getLinkEntityName($entityName, $linkParams); + //print_r($entityDefs[$linkEntityName]['links']); + //print_r($convertedMeta[$linkEntityName]); + + $currentType = $linkParams['type']; + $parentType = ''; + + $foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$linkEntityName]); + + $method = $currentType; + if ($foreignLink !== false) { + $method .= '-'.$foreignLink['params']['type']; + } + $method = Util::toCamelCase($method); + + + /*if ($method == 'belongsToParent') { + die($entityName.' - '.$linkName); + }*/ + + + if (method_exists($this->getLinkConverter(), $method)) { + $convertedLink = $this->getLinkConverter()->process($method, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink); + //print_r($convertedLink); + } + + //echo $method.' = '.$currentType.' - '.$foreignLink['type'].'
'; + + + } + + return $convertedMeta; + } + + + /** + * Get foreign Link + * + * @param string $parentLinkName + * @param array $parentLinkParams + * @param array $currentEntityDefs + * + * @return array - in format array('name', 'params') + */ + protected function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs) + { + if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) { + return array( + 'name' => $parentLinkParams['foreign'], + 'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']], + ); + } + + $parentLinkName = strtolower($parentLinkName); + + foreach($currentEntityDefs['links'] as $linkName => $linkParams) { + if (isset($linkParams['foreign']) && strtolower($linkParams['foreign']) == $parentLinkName) { + return array( + 'name' => $linkName, + 'params' => $linkParams, + ); + } + } + + return false; + } + + + + protected function getInitValues(array $fieldParams) + { + $values = array(); + foreach($this->fieldAccordances as $espoType => $doctrineType) { + + if (isset($fieldParams[$espoType]) && !empty($fieldParams[$espoType])) { + + if (is_array($doctrineType)) { + + $conditionRes = false; + if (!is_array($fieldParams[$espoType])) { + $conditionRes = preg_match('/'.$doctrineType['condition'].'/i', $fieldParams[$espoType]); + } + + if (!$conditionRes || ($conditionRes && $conditionRes === $doctrineType['conditionEquals']) ) { + $value = is_array($fieldParams[$espoType]) ? json_encode($fieldParams[$espoType]) : $fieldParams[$espoType]; + $values = Util::merge( $values, Util::replaceInArray('{0}', $value, $doctrineType['value']) ); + } + } else { + $values[$doctrineType] = $fieldParams[$espoType]; + } + + } + } + + return $values; + } + +} + + +?> \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/Converter/Link.php b/application/Espo/Core/Doctrine/Converter/Link.php new file mode 100644 index 0000000000..cbf0aae490 --- /dev/null +++ b/application/Espo/Core/Doctrine/Converter/Link.php @@ -0,0 +1,169 @@ +metadata = $metadata; + + $this->association = new \Espo\Core\Doctrine\Converter\Association(); + } + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getAssociation() + { + return $this->association; + } + + + public function getLinkEntityName($entityName, $link) + { + if (isset($link['params'])) { + return isset($link['params']['entity']) ? $link['params']['entity'] : $entityName; + } + 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']); + + + if (method_exists($this, $method)) { + return $this->$method($params, $foreignParams); + } + + return false; + } + + + + protected function belongsTo($params, $foreignParams) + { + return $this->getAssociation()->manyToOneUnidirectional($params, $foreignParams); + } + + + //TODO: hook for teams + protected function hasMany($params, $foreignParams) + { + return $this->getAssociation()->oneToManyUnidirectionalWithJoinTable($params, $foreignParams); + } + + + protected function hasManyHasMany($params, $foreignParams) + { + return $this->getAssociation()->manyToManyBidirectional($params, $foreignParams); + } + + protected function hasOne($params, $foreignParams) + { + return $this->getAssociation()->oneToOneUnidirectional($params, $foreignParams); + } + + protected function hasOneBelongsTo($params, $foreignParams) + { + return $this->getAssociation()->oneToOneBidirectional($params, $foreignParams); + } + + + protected function belongsToParent($params, $foreignParams) + { + return $this->getAssociation()->oneToManySelfReferencing($params, $foreignParams); + } + + + + + /* + +[0] => belongsTo + [1] => belongsToParent + [2] => hasManyBelongsToParent + +[3] => hasMany + [4] => hasChildrenBelongsToParent + +[5] => hasOne + +[6] => hasManyHasMany + [7] => hasManyBelongsTo + [8] => hasChildrenHasMany + [9] => hasChildren + [10] => belongsToHasMany + [11] => joint + + + [0] => belongsTo + [1] => belongsToParent + [2] => hasManyBelongsToParent + [3] => hasMany + [4] => hasChildrenBelongsToParent + [5] => belongsToParentHasChildren + [6] => hasOne + [7] => hasManyBelongsTo + [8] => hasManyHasMany + [9] => belongsToHasMany + [10] => joint + + + + + [0] => belongsTo + [1] => belongsToParent + [2] => hasManyBelongsToParent + [3] => hasMany + [4] => hasChildrenBelongsToParent + [5] => belongsToParentHasChildren + [6] => hasOne + [7] => hasManyHasMany + [8] => hasManyBelongsTo + [9] => hasChildrenHasMany + [10] => hasChildren + [11] => belongsToHasMany + [12] => joint + */ + +} \ No newline at end of file diff --git a/application/Espo/Core/Doctrine/EspoConverter.php b/application/Espo/Core/Doctrine/EspoConverter.php deleted file mode 100644 index d68a9ae361..0000000000 --- a/application/Espo/Core/Doctrine/EspoConverter.php +++ /dev/null @@ -1,327 +0,0 @@ -entityManager = $entityManager; - $this->metadata = $metadata; - $this->fileManager = $fileManager; - - $this->doctrineHelper = new \Espo\Core\Doctrine\Helper($this->getEntityManager()->getWrapped()); - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - protected function getMetadata() - { - return $this->metadata; - } - - protected function getFileManager() - { - return $this->fileManager; - } - - protected function getSchemaTool() - { - return $this->schemaTool; - } - - protected function getDisconnectedClassMetadataFactory() - { - return $this->disconnectedClassMetadataFactory; - } - - protected function getEntityGenerator() - { - return $this->entityGenerator; - } - - - - public function setMeta(array $meta) - { - $this->meta = $meta; - } - - protected function getMeta() - { - return $this->meta; - } - - protected function getFieldMeta($type = '') - { - $meta = $this->getMeta(); - if (empty($type)) { - return $meta['fields']; - } - else if (isset($meta['fields'][$type])) { - return $meta['fields'][$type]; - } - - return false; - } - - - /** - * Metadata conversion from Espo format into Doctrine - * - * @param object $meta - * - * @return bool - */ - public function convertToDoctrine() - { - $GLOBALS['log']->add('Debug', 'Metadata:get() - converting to doctrine metadata'); - - $meta = $this->getMetadata()->getAll(); - - return; //TODO - $this->setMeta($meta); - - $cacheDir = $this->getMetadata()->getMetaConfig()->doctrineCache; - $this->getFileManager()->removeFilesInDir($cacheDir); //remove all existing files - - //create files named like "Espo.Entities.User.php" - - $convertedMeta = array(); - foreach($meta[$this->getMetadata()->getMetaConfig()->espoMetadataName] as $entityName => $metaRow) { - - $convertedMeta[$entityName] = $this->convert($entityName, $metaRow); - //$convertedMeta = Util::merge($convertedMeta, $this->convert($entityName, $metaRow)); //for link is need to define for two entities at once - } - - - /*echo '
';
-		print_r($convertedMeta);
-        exit;*/
-
-		//save doctrine meta to files
-		$result= true;
-		foreach ($convertedMeta as $entityName => $doctineMeta) {
-			$entityFullName = $this->getMetadata()->getEntityPath($entityName);
-			$doctrineMeta = array($entityFullName => $doctineMeta);
-
-            //create a doctrine metadata file
-			$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;
-	}
-
-
-	/**
-	* 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;
-	}
-
-
-	/**
-	* Metadata conversion from Espo format into Doctrine
-    *
-	* @param string $name
-	* @param array $data
-	*
-	* @return array
-	*/
-	//NEED TO CHANGE
-	protected function convert($entityName, $meta)
-	{
-		if (empty($meta)) {
-	    	$GLOBALS['log']->add('ERROR', 'EspoConverter:convert(), Entity:'.$entityName.' - metadata cannot be converted into Doctrine format');
-		}
-
-		//conversion functionality
-		$outputMeta = array(
-			'type' => 'entity',
-			'table' => $entityName, //TODO: if need to convert to underscore
-			'id' => array(
-				'id' => array(
-			        'type' => 'string',
-			        'generator' => array('strategy' => 'UUID'),
-				)
-			),
-			'fields' => array(
-			),
-		);
-
-		$outputMeta = Util::merge($outputMeta, $this->convertFields($entityName, $meta));
-		//$outputMeta = Util::merge($outputMeta, $this->convertLinks($meta));
-		//END: conversion functionality
-
-
-        return $outputMeta;
-	}
-
-
-
-	/*It can be moved to separate file*/
-	protected function convertFields($entityName, array $meta)
-	{
-		$metaFields = $meta['fields'];
-
-		$convertedMetaFields = array();
-		foreach($meta['fields'] as $fieldName => $fieldParams) {
-
-			//set default type if exists
-        	if (!isset($fieldParams['type']) || !empty($fieldParams['type'])) {
-        		$GLOBALS['log']->add('WARNING', 'Field type does not exist for '.$entityName.':'.$fieldName.'. Use default type ['.$this->defaultFieldType.']');
-				$fieldParams['type'] = $this->defaultFieldType;
-        	} //END: set default type if exists
-
-			$fieldMeta = $this->getFieldMeta($fieldParams['type']);
-
-			//check if field need to be saved in database
-        	if ( (isset($fieldParams['db']) && $fieldParams['db'] === false) || (isset($fieldMeta['database']['db']) && !$fieldMeta['database']['db'] === false) ) {
-        		continue;
-        	} //END: check if field need to be saved in database
-
-            $convertedMetaFields[$fieldName] = $this->getInitValues($fieldParams);
-
-
-			/*echo '
';
-			print_r($convertedMetaFields[$fieldName]);
-			exit;*/
-
-            //convert type
-            $convertedMetaFields[$fieldName]['type'] = $this->getFieldType($fieldParams['type']);
-			//END: convert type
-		}
-
-
-        /*echo '
'.$entityName.'
';
-		print_r($convertedMetaFields); */
-	}
-
-    protected function getFieldType($espoType)
-	{
-		$fieldMeta = $this->getFieldMeta($espoType);
-
-        if (isset($fieldMeta['database']['type']) && !empty($fieldMeta['database']['type'])) {
-           	return $fieldMeta['database']['type'];
-		}
-
-		return $espoType;
-	}
-
-	protected function getInitValues(array $fieldParams)
-	{
-		//pair espo:doctrine
-		$convertRules = array(
-			'type' => 'type',
-			'maxLength' => 'length',
-			'default' => array(
-			   'condition' => '!(^javascript)',
-			   'json' => '{"options":{"default":{0}}}',
-			),
-		);
-
-
-		$values = array();
-		foreach($convertRules as $espoType => $doctrineType) {
-
-        	if (isset($fieldParams[$espoType]) && !empty($fieldParams[$espoType])) {
-
-				if (is_array($doctrineType))  {
-
-					//print_r($fieldParams);
-					//echo  $doctrineType['condition'].'    '.$fieldParams[$espoType];
-
-                	//if (preg_match('/'.$doctrineType['condition'].'/i', $fieldParams[$espoType])) {
-                		$jsonValue = json_encode($fieldParams[$espoType]);
-						$jsonRes = str_replace('{0}', $jsonValue, $doctrineType['json']);
-                        $values = Util::merge($values, json_decode($jsonRes, true));
-                	//}
-				} else {
-                	$values[$doctrineType] = $fieldParams[$espoType];
-				}
-			}
-		}
-
-		return $values;
-	}
-
-
-
-
-	protected function convertLinks(array $meta)
-	{
-		$metaFields = $meta['links'];
-
-	}
-
-}
-
-
-?>
\ No newline at end of file
diff --git a/application/Espo/Core/Doctrine/Helper.php b/application/Espo/Core/Doctrine/Helper.php
index 5a2a75efc6..6ceaab3578 100644
--- a/application/Espo/Core/Doctrine/Helper.php
+++ b/application/Espo/Core/Doctrine/Helper.php
@@ -13,7 +13,7 @@ class Helper
 	private $entityGenerator;
 
 
-	public function __construct(\Espo\Core\EntityManager $entityManager)
+	public function __construct(\Doctrine\ORM\EntityManager $entityManager)
 	{
 		$this->entityManager = $entityManager;
 
@@ -45,4 +45,57 @@ class Helper
 	}
 
 
+
+	/**
+	* 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/Utils/Util.php b/application/Espo/Core/Utils/Util.php
index 56655c63b6..909bfea312 100644
--- a/application/Espo/Core/Utils/Util.php
+++ b/application/Espo/Core/Utils/Util.php
@@ -49,13 +49,13 @@ class Util
 	*
 	* @return string
 	*/
-	public static function toCamelCase($name, $capitaliseFirstChar=false)
+	public static function toCamelCase($name, $capitaliseFirstChar = false, $symbol = '-')
 	{
 		if($capitaliseFirstChar) {
 			$name[0] = strtoupper($name[0]);
 		}
 		$func = create_function('$c', 'return strtoupper($c[1]);');
-		return preg_replace_callback('/-([a-z])/', $func, $name);
+		return preg_replace_callback('/'.$symbol.'([a-z])/', $func, $name);
 	}
 
 	/**
@@ -66,10 +66,10 @@ class Util
 	*
 	* @return string
 	*/
-	public static function fromCamelCase($name)
+	public static function fromCamelCase($name, $symbol = '-')
 	{
 		$name[0] = strtolower($name[0]);
-		$func = create_function('$c', 'return "-" . strtolower($c[1]);');
+		$func = create_function('$c', 'return "'.$symbol.'" . strtolower($c[1]);');
 		return preg_replace_callback('/([A-Z])/', $func, $name);
 	}
 
@@ -186,6 +186,58 @@ class Util
         return is_array($object) ? array_map("static::objectToArray", $object) : $object;
 	}
 
+
+	/**
+    * Get Naming according to prefix or postfix type
+	*
+	* @param string $name
+	* @param string $prePostFix
+	* @param string $type
+	*
+	* @return string
+	*/
+	public static function getNaming($name, $prePostFix, $type = 'prefix', $symbol = '-')
+	{
+		if ($type == 'prefix') {
+        	return static::toCamelCase($prePostFix.$symbol.$name, false, $symbol);
+		} else if ($type == 'postfix') {
+        	return static::toCamelCase($name.$symbol.$prePostFix, false, $symbol);
+		}
+
+		return null;
+	}
+
+
+	/**
+    * Replace $search in array recursively
+	*
+	* @param string $search
+	* @param string $replace
+	* @param string $array
+	* @param string $isKeys
+	*
+	* @return array
+	*/
+	public static function replaceInArray($search = '', $replace = '', $array = false, $isKeys = true)
+	{
+		if (!is_array($array)) {
+			return str_replace($search, $replace, $array);
+		}
+
+		$newArr = array();
+		foreach ($array as $key => $value) {
+			$addKey = $key;
+			if ($isKeys) { //Replace keys
+				$addKey = str_replace($search, $replace, $key);
+			}
+
+			// Recurse
+			$newArr[$addKey] = static::replaceInArray($search, $replace, $value, $isKeys);
+		}
+
+		return $newArr;
+	}
+
 }
 
 
diff --git a/application/Espo/Resources/metadata/fields/array.json b/application/Espo/Resources/metadata/fields/array.json
index a98f0c50a0..e10385bf47 100644
--- a/application/Espo/Resources/metadata/fields/array.json
+++ b/application/Espo/Resources/metadata/fields/array.json
@@ -17,5 +17,8 @@
    "search":{
       "basic":false,
       "advanced":false
+   },
+   "database":{
+      "type":"json_array"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/duration.json b/application/Espo/Resources/metadata/fields/duration.json
new file mode 100644
index 0000000000..c936f61d65
--- /dev/null
+++ b/application/Espo/Resources/metadata/fields/duration.json
@@ -0,0 +1,5 @@
+{
+   "database":{
+      "type":"integer"
+   }
+}
diff --git a/testAuth.php b/testAuth.php
index cbf74b5601..15e8a25ceb 100644
--- a/testAuth.php
+++ b/testAuth.php
@@ -11,7 +11,7 @@ class Auth extends \Slim\Middleware
 
 	private $container;
 
-	public function __construct(\Doctrine\ORM\EntityManager $entityManager, \Espo\Core\Container $container)
+	public function __construct(\Espo\Core\EntityManager $entityManager, \Espo\Core\Container $container)
 	{
 		$this->entityManager = $entityManager;
 		$this->container = $container;
@@ -49,7 +49,7 @@ class Auth extends \Slim\Middleware
 			$username = $authKey;
 			$password = $authSec;
 
-		    $user = $this->entityManager->getRepository('\Espo\Entities\User')->findOneBy(array('username' => $username));
+		    $user = $this->entityManager->getRepository('User')->findOneBy(array('username' => $username));
 			if ($user) {
 				if ($password == $user->getPassword()) {
 					$this->container->setUser($user);
diff --git a/tests/Espo/Core/Doctrine/EspoConverterTest.php b/tests/Espo/Core/Doctrine/EspoConverterTest.php
new file mode 100644
index 0000000000..9cad46854d
--- /dev/null
+++ b/tests/Espo/Core/Doctrine/EspoConverterTest.php
@@ -0,0 +1,45 @@
+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/UtilTest.php b/tests/Espo/Core/Utils/UtilTest.php
index c208ad0a0d..4cda010268 100644
--- a/tests/Espo/Core/Utils/UtilTest.php
+++ b/tests/Espo/Core/Utils/UtilTest.php
@@ -180,6 +180,38 @@ class UtilTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($testResult, Util::objectToArray($testObj));
 	}
 
+	function testGetNaming()
+	{
+    	$this->assertEquals('myPrefixMyName', Util::getNaming('myName', 'myPrefix', 'prefix'));
+
+    	$this->assertEquals('myNameMyPostfix', Util::getNaming('myName', 'myPostfix', 'postfix'));
+    	$this->assertEquals('myNameMyPostfix', Util::getNaming('my_name', 'myPostfix', 'postfix', '_'));
+    	$this->assertEquals('myNameMyPostfix', Util::getNaming('my_name', 'my_postfix', 'postfix', '_'));
+	}
+
+	function testReplaceInArray()
+	{
+		$testArray = array(
+			'option' => array(
+				'default' => '{0}',
+		         'testKey' => array(
+				 	'{0}' => 'testVal',
+				 ),
+			),
+		);
+
+		$testResult = array(
+			'option' => array(
+				'default' => 'DONE',
+		         'testKey' => array(
+				 	'DONE' => 'testVal',
+				 ),
+			),
+		);
+
+		$this->assertEquals($testResult, Util::replaceInArray('{0}', 'DONE', $testArray, true));
+	}
+
 
 	/*function testGetScopeModuleName()
 	{