diff --git a/application/Espo/Core/Application.php b/application/Espo/Core/Application.php index b1a5412f34..900ea94590 100644 --- a/application/Espo/Core/Application.php +++ b/application/Espo/Core/Application.php @@ -13,7 +13,7 @@ class Application private $slim; - + private $doctrineConverter; /** * Constructor @@ -22,13 +22,16 @@ class Application { $this->container = new Container(); - $GLOBALS['log'] = $this->log = $this->container->get('log'); + $GLOBALS['log'] = $this->log = $this->container->get('log'); set_error_handler(array($this->getLog(), 'catchError'), E_ALL); set_exception_handler(array($this->getLog(), 'catchException')); $this->serviceFactory = new ServiceFactory($this->container); $this->slim = $this->container->get('slim'); + $this->metadata = $this->container->get('metadata'); + + $this->initMetadata(); } public function getSlim() @@ -36,6 +39,11 @@ class Application return $this->slim; } + public function getMetadata() + { + return $this->metadata; + } + public function getContainer() { return $this->container; @@ -51,6 +59,11 @@ class Application return $this->serviceFactory; } + protected function getDoctrineConverter() + { + return $this->doctrineConverter; + } + public function run($name = 'default') { $this->routeHooks(); @@ -58,6 +71,26 @@ class Application $this->getSlim()->run(); } + + protected function initMetadata() + { + $isNotCached = !$this->getMetadata()->isCached(); + + $this->getMetadata()->init($isNotCached); + + if ($isNotCached) { + $doctrineConverter = new \Espo\Core\Doctrine\EspoConverter($this->container->get('entityManager'), $this->getMetadata(), $this->container->get('fileManager')); + + if ($doctrineConverter->convertToDoctrine()) { + try{ + $doctrineConverter->rebuildDatabase(); + } catch (\Exception $e) { + $GLOBALS['log']->add('EXCEPTION', 'Fault to rebuildDatabase'.'. Details: '.$e->getMessage()); + } + } + } + } + protected function routeHooks() { $container = $this->getContainer(); @@ -116,14 +149,14 @@ class Application $controllerParams[$key] = $value; } - $controllerName = ucfirst($controllerParams['controller']); + $controllerName = ucfirst($controllerParams['controller']); if (!empty($controllerParams['action'])) { $actionName = $controllerParams['action']; } else { $httpMethod = strtolower($slim->request()->getMethod()); $actionName = $container->get('config')->get('crud')->$httpMethod; - } + } try { $controllerManager = new \Espo\Core\ControllerManager($container, $serviceFactory); @@ -164,7 +197,9 @@ class Application ); $this->getSlim()->get('/', function() { - return "EspoCRM REST API"; + return $template = <<EspoCRM REST API!!! +EOT; }); $this->getSlim()->get('/app/user/', function() { @@ -207,22 +242,8 @@ class Application 'scope' => ':controller', ); })->via('PATCH'); - - - - $this->getSlim()->get('/:controller', function() { - return array( - 'controller' => ':controller', - 'action' => 'index', - ); - }); - $this->getSlim()->post('/:controller', function() { - return array( - 'controller' => ':controller', - 'action' => 'create', - ); - }); + /*$this->getSlim()->get('/:controller/:id', function() { return array( @@ -232,7 +253,12 @@ class Application ); }); - + $this->getSlim()->post('/:controller', function() { + return array( + 'controller' => ':controller', + 'action' => 'create', + ); + }); $this->getSlim()->put('/:controller/:id', function() { return array( diff --git a/application/Espo/Core/Container.php b/application/Espo/Core/Container.php index 1c2982516f..62031ba721 100644 --- a/application/Espo/Core/Container.php +++ b/application/Espo/Core/Container.php @@ -81,7 +81,6 @@ class Container return new \Espo\Core\Utils\Log( $this->get('fileManager'), $this->get('output'), - $this->get('resolver'), (object) array( 'options' => $this->get('config')->get('logger'), 'datetime' => $this->get('datetime')->getDatetime(), @@ -99,7 +98,6 @@ class Container private function loadMetadata() { return new \Espo\Core\Utils\Metadata( - $this->get('entityManager'), $this->get('config'), $this->get('fileManager'), $this->get('uniteFiles') @@ -116,13 +114,6 @@ class Container ); } - private function loadResolver() - { - return new \Espo\Core\Utils\Resolver( - $this->get('metadata') - ); - } - private function loadDatetime() { return new \Espo\Core\Utils\Datetime( @@ -151,14 +142,6 @@ class Container public function setUser($user) { $this->data['user'] = $user; - } - - /*private function loadUser() - { - return new \Espo\Core\Utils\User( - $this->get('entityManager'), - $this->get('config') - ); - }*/ + } } diff --git a/application/Espo/Core/Doctrine/EspoConverter.php b/application/Espo/Core/Doctrine/EspoConverter.php index 7acaf9e76c..9db0af48d4 100644 --- a/application/Espo/Core/Doctrine/EspoConverter.php +++ b/application/Espo/Core/Doctrine/EspoConverter.php @@ -2,18 +2,30 @@ namespace Espo\Core\Doctrine; +use Espo\Core\Utils\Util; + class EspoConverter { private $entityManager; private $metadata; + private $fileManager; private $schemaTool; private $disconnectedClassMetadataFactory; private $entityGenerator; - public function __construct(\Doctrine\ORM\EntityManager $entityManager, \Espo\Core\Utils\Metadata $metadata) + protected $defaultFieldType = 'varchar'; + + /** + * @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->schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->getEntityManager()); $this->entityGenerator = new \Doctrine\ORM\Tools\EntityGenerator(); @@ -32,6 +44,10 @@ class EspoConverter return $this->metadata; } + protected function getFileManager() + { + return $this->fileManager; + } protected function getSchemaTool() { @@ -50,6 +66,80 @@ class EspoConverter + 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()->get(); + + 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
     *
@@ -106,24 +196,133 @@ class EspoConverter
     *
 	* @param string $name
 	* @param array $data
-	* @param bool $withName - different return array. If $withName=false, then return is "array()"; $withName=true, then array('name'=>$entityName, 'meta'=>$doctrineMeta);
 	*
 	* @return array
 	*/
 	//NEED TO CHANGE
-	function convert($name, $data, $withName=false)
+	protected function convert($entityName, $meta)
 	{
-		//HERE SHOULD BE CONVERSION FUNCTIONALITY
-		$entityFullName= $this->getMetadata()->getEntityPath($name, '\\');   
+		if (empty($meta)) {
+	    	$GLOBALS['log']->add('ERROR', 'EspoConverter:convert(), Entity:'.$entityName.' - metadata cannot be converted into Doctrine format');
+		}
 
-		$doctrineMeta= array(
-            $entityFullName => $data
+		//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(
+			),
 		);
 
-		if ($withName) {
-			return array('name'=>$entityFullName, 'meta'=>$doctrineMeta);
+		$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
 		}
-        return $doctrineMeta;
+
+
+        /*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'];
+
 	}
 
 }
diff --git a/application/Espo/Core/Doctrine/Helper.php b/application/Espo/Core/Doctrine/Helper.php
new file mode 100644
index 0000000000..7b60f88cd8
--- /dev/null
+++ b/application/Espo/Core/Doctrine/Helper.php
@@ -0,0 +1,20 @@
+entityManager = $entityManager;
+	}
+
+	protected function getEntityManager()
+	{
+		return $this->entityManager;
+	}
+
+
+}
\ No newline at end of file
diff --git a/application/Espo/Core/Doctrine/Types/Password.php b/application/Espo/Core/Doctrine/Types/Password.php
new file mode 100644
index 0000000000..e85b4c39f1
--- /dev/null
+++ b/application/Espo/Core/Doctrine/Types/Password.php
@@ -0,0 +1,32 @@
+getVarcharTypeDeclarationSQL($fieldDeclaration);
+		//return "MD5";
+    }
+
+    /*public function convertToPHPValue($value, AbstractPlatform $platform)
+    {
+        return $value;
+    }
+
+    public function convertToDatabaseValue($value, AbstractPlatform $platform)
+    {
+        return $value;
+    } */
+
+    public function getName()
+    {
+        return self::PASSWORD;
+    }
+}
+
diff --git a/application/Espo/Core/Utils/Api/Auth.php b/application/Espo/Core/Utils/Api/Auth.php
index a44764c64d..0e234db4ca 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(\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;
diff --git a/application/Espo/Core/Utils/Log.php b/application/Espo/Core/Utils/Log.php
index 60af52f682..e3a1237df1 100644
--- a/application/Espo/Core/Utils/Log.php
+++ b/application/Espo/Core/Utils/Log.php
@@ -59,15 +59,13 @@ class Log
 
 	private $fileManager;
 	private $output;
-	private $resolver;
 	private $params;
 
 
-	public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Api\Output $output, \Espo\Core\Utils\Resolver $resolver, \stdClass $params)    
+	public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Api\Output $output, \stdClass $params)
 	{
 		$this->fileManager = $fileManager;
 		$this->output = $output;
-		$this->resolver = $resolver;
 		$this->params = $params;
 	}
 
@@ -83,11 +81,6 @@ class Log
 		return $this->output;
 	}
 
-	protected function getResolver()
-	{
-		return $this->resolver;
-	}
-
 	protected function getParams()
 	{
 		return $this->params;
@@ -120,15 +113,15 @@ class Log
 	* @param integer $Exception
 	* @return bool
 	*/
-	public function catchException($Exception, $useResolver = true)
+	public function catchException($Exception)
     {
 		$errNo = $Exception->getCode();
 		$errorMessage = get_class($Exception).' - '.$Exception->getMessage();
 
  		//try to resolve the problem automatically
- 		if ($useResolver) {
+ 		/*if ($useResolver) {
         	$this->getResolver()->handle($Exception);
- 		}
+ 		} */
 
         $errorType= $this->phpErrorTypes[$errNo];
 		if (empty($errorType)) {
diff --git a/application/Espo/Core/Utils/Metadata.php b/application/Espo/Core/Utils/Metadata.php
index d3bf295d1a..a34fa18d30 100644
--- a/application/Espo/Core/Utils/Metadata.php
+++ b/application/Espo/Core/Utils/Metadata.php
@@ -9,27 +9,19 @@ class Metadata
 
 	protected $metadataConfig;
 	protected $doctrineMetadataName = 'defs'; //Metadata "defs" uses for creating the metadata of Doctri
+	protected $meta;
 
 	protected $scopes= array();
 
-	private $entityManager;
 	private $config;
-	private $doctrineConverter;
 	private $uniteFiles;
 	private $fileManager;
 
-	public function __construct(\Doctrine\ORM\EntityManager $entityManager, \Espo\Core\Utils\Config $config, \Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\File\UniteFiles $uniteFiles)
+	public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\File\UniteFiles $uniteFiles)
 	{
-		$this->entityManager = $entityManager;
 		$this->config = $config;
 		$this->uniteFiles = $uniteFiles;
 		$this->fileManager = $fileManager;
-		$this->doctrineConverter = new \Espo\Core\Doctrine\EspoConverter($entityManager, $this);
-	}
-
-	protected function getEntityManager()
-	{
-		return $this->entityManager;
 	}
 
 	protected function getConfig()
@@ -37,10 +29,7 @@ class Metadata
 		return $this->config;
 	}
 
-	protected function getDoctrineConverter()
-	{
-		return $this->doctrineConverter;
-	}
+
 
 	protected function getUniteFiles()
 	{
@@ -53,6 +42,39 @@ class Metadata
 	}
 
 
+	public function isCached()
+	{
+    	if (!$this->getConfig()->get('useCache')) {
+           	return false;
+		}
+
+		if (file_exists($this->getMetaConfig()->metadataCacheFile)) {
+			return true;
+		}
+
+		return false;
+	}
+
+
+    public function init($reload = false)
+	{
+       	$data= $this->getMetadataOnly(false, $reload);
+		if ($data === false) {
+			$GLOBALS['log']->add('FATAL', 'Metadata:init() - metadata has not been created');
+		}
+
+		$this->meta = $data;
+
+		if ($reload) {
+        	//save medatada to a cache file
+	        $isSaved = $this->getFileManager()->setContentPHP($data, $this->getMetaConfig()->metadataCacheFile);
+			if ($isSaved === false) {
+	        	$GLOBALS['log']->add('FATAL', 'Metadata:init() - metadata has not been saved to a cache file');
+			}
+		}
+	}
+
+
 	/**
     * Get Metadata context
 	*
@@ -61,37 +83,16 @@ class Metadata
 	*
 	* @return json | array
 	*/
-	//HERE --- ADD CREATING DOCTRINE METADATA
-	public function get($isJSON = true, $reload = false)
+	public function get($isJSON = false, $reload = false)
 	{
-		$config= $this->getMetaConfig();
-
-		if (!$this->getConfig()->get('useCache')) {
-           	$reload = true;
+		if ($reload) {
+			$this->init();
 		}
 
-		if (!file_exists($config->cacheFile) || $reload) {
-        	$data= $this->getMetadataOnly(false, true);
-			if ($data === false) {
-				return false;
-			}
-
-			//save medatada to cache files
-	        $this->getFileManager()->setContentPHP($data, $this->getMetaConfig()->cacheFile);
-
-			$GLOBALS['log']->add('Debug', 'Metadata:get() - converting to doctrine metadata');
-            if ($this->convertToDoctrine($data)) {
-            	$GLOBALS['log']->add('Debug', 'Metadata:get() - database rebuild');
-
-				try{
-	        		$this->getDoctrineConverter()->rebuildDatabase();
-			   	} catch (\Exception $e) {
-				  	$GLOBALS['log']->add('EXCEPTION', 'Try to rebuildDatabase'.'. Details: '.$e->getMessage());
-				}
-            }
-		}
-
-		return $this->getMetadataOnly($isJSON, false);
+		if ($isJSON) {
+        	return Json::encode($this->meta);
+        }
+		return $this->meta;
 	}
 
 
@@ -104,25 +105,20 @@ class Metadata
 	*
 	* @return json | array
 	*/
-
 	public function getMetadataOnly($isJSON = true, $reload = false)
 	{
 		$config= $this->getMetaConfig();
 
-		if (!$this->getConfig()->get('useCache')) {
-        	$reload = true;
-		}
-
 		$data = false;
-		if (!file_exists($config->cacheFile) || $reload) {
+		if (!file_exists($config->metadataCacheFile) || $reload) {
         	$data= $this->uniteFiles($config, true);
 
 			if ($data === false) {
             	$GLOBALS['log']->add('FATAL', 'Metadata:getMetadata() - metadata unite file cannot be created');
 			}
 		}
-        else if (file_exists($config->cacheFile)) {
-			$data= $this->getFileManager()->getContent($config->cacheFile);
+        else if (file_exists($config->metadataCacheFile)) {
+			$data= $this->getFileManager()->getContent($config->metadataCacheFile);
 		}
 
 		if ($isJSON) {
@@ -146,66 +142,32 @@ class Metadata
 	*/
 	public function set($data, $type, $scope)
 	{
-		$fullPath= $this->getMetaConfig()->corePath;
-		$moduleName= $this->getScopeModuleName($scope);
+		$fullPath = $this->getMetaConfig()->corePath;
+		$moduleName = $this->getScopeModuleName($scope);
 
 		if ($moduleName !== false) {
-        	$fullPath= str_replace('{*}', $moduleName, $this->getMetaConfig()->customPath);
+        	$fullPath = str_replace('{*}', $moduleName, $this->getMetaConfig()->customPath);
 		}
-		$fullPath= Util::concatPath($fullPath, $type);
+		$fullPath = Util::concatPath($fullPath, $type);
 
         //merge data with defaults values
-        $defaults= $this->getUniteFiles()->loadDefaultValues($type, 'metadata');
+        $defaults = $this->getUniteFiles()->loadDefaultValues($type, 'metadata');
 
-        $decoded= Json::getArrayData($data);
-        $mergedValues= Util::merge($defaults, $decoded);
-		$data= Json::encode($mergedValues);
+        $decoded = Json::getArrayData($data);
+        $this->meta = Util::merge($defaults, $decoded);
+		$data= Json::encode($this->meta);
         //END: merge data with defaults values
 
 		$result= $this->getFileManager()->setContent($data, $fullPath, $scope.'.json');
 
 		//create classes only for "defs" metadata
-		if ($type == $this->doctrineMetadataName) {
+		/*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;
-	}
-
-
-    /**
-	* Metadata conversion from Espo format into Doctrine
-    *
-	* @param object $metadata
-	*
-	* @return bool
-	*/
-	protected function convertToDoctrine($metadata)
-	{
-		$cacheDir= $this->getMetaConfig()->doctrineCache;
-
-		//remove all existing files
-		$this->getFileManager()->removeFilesInDir($cacheDir);
-
-		//create files named like "Espo.Entities.User.php"
-		$result= true;
-        foreach($metadata[$this->doctrineMetadataName] as $entityName => $meta) {
-	        $doctrineMetaWithName= $this->getDoctrineConverter()->convert($entityName, $meta, true);
-
-            if (empty($doctrineMetaWithName)) {
-	        	$GLOBALS['log']->add('FATAL', 'Metadata:convertToDoctrine(), Entity:'.$entityName.' - metadata cannot be converted into Doctrine format');
-				return false;
-			}
-
-			//create a doctrine metadata file
-			$fileName= str_replace('\\', '.', $doctrineMetaWithName['name']).'.php';
-            $result&= $this->getFileManager()->setContent($this->getFileManager()->getPHPFormat($doctrineMetaWithName['meta']), $cacheDir, $fileName);
-			//END: create a doctrine metadata file
-        }
+		}*/
 
         return $result;
 	}
@@ -277,7 +239,7 @@ class Metadata
 
         $scopes = array();
 		foreach($metadata['scopes'] as $name => $details) {
-        	$scopes[$name] = isset($details['module']) ? $details['module'] : '';
+        	$scopes[$name] = isset($details['module']) ? $details['module'] : false;
 		}
 
 		return $this->scopes = $scopes;
@@ -369,14 +331,14 @@ class Metadata
 	*
 	* @return object
 	*/
-	protected function getMetaConfig()
+	public function getMetaConfig()
 	{
 		if (isset($this->metadataConfig) && is_object($this->metadataConfig)) {
     		return $this->metadataConfig;
     	}
 
 		$this->metadataConfig = $this->getConfig()->get('metadataConfig');
-		$this->metadataConfig->cacheFile= Util::concatPath($this->metadataConfig->cachePath, $this->metadataConfig->name).'.php';
+		$this->metadataConfig->metadataCacheFile= Util::concatPath($this->metadataConfig->cachePath, $this->metadataConfig->name).'.php';
 
 		return $this->metadataConfig;
 	}
diff --git a/application/Espo/Core/defaults/systemConfig.php b/application/Espo/Core/defaults/systemConfig.php
index 11c4b57e79..801076def3 100644
--- a/application/Espo/Core/defaults/systemConfig.php
+++ b/application/Espo/Core/defaults/systemConfig.php
@@ -21,6 +21,7 @@ return array (
     'corePath' => 'application/Espo/Resources/metadata',
     'customPath' => 'application/Espo/Modules/{*}/Resources/metadata',
     'doctrineCache' => 'data/cache/doctrine/metadata',
+    'espoMetadataName' => 'entityDefs',
   ),
 
   'layoutConfig' =>
diff --git a/application/Espo/Resources/metadata/fields/autoincrement.json b/application/Espo/Resources/metadata/fields/autoincrement.json
index ec2660b62d..c32640cb6f 100644
--- a/application/Espo/Resources/metadata/fields/autoincrement.json
+++ b/application/Espo/Resources/metadata/fields/autoincrement.json
@@ -4,5 +4,9 @@
    "search":{
       "basic":false,
       "advanced":true
+   },
+   "database":{
+      "type":"integer",
+      "autoincrement":true
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/base.json b/application/Espo/Resources/metadata/fields/base.json
index 0f02c7a6c5..b9b2a2858d 100644
--- a/application/Espo/Resources/metadata/fields/base.json
+++ b/application/Espo/Resources/metadata/fields/base.json
@@ -2,5 +2,8 @@
    "search":{
       "basic":false,
       "advanced":false
+   },
+   "database":{
+      "db": false 
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/bool.json b/application/Espo/Resources/metadata/fields/bool.json
index 5db27091c4..85dad49a48 100644
--- a/application/Espo/Resources/metadata/fields/bool.json
+++ b/application/Espo/Resources/metadata/fields/bool.json
@@ -8,5 +8,8 @@
    "search":{
       "basic":false,
       "advanced":true
+   },
+   "database":{
+      "type":"boolean"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/email.json b/application/Espo/Resources/metadata/fields/email.json
index 1bccdcce9f..e8e22e7401 100644
--- a/application/Espo/Resources/metadata/fields/email.json
+++ b/application/Espo/Resources/metadata/fields/email.json
@@ -13,5 +13,8 @@
    "search":{
       "basic":true,
       "advanced":true
+   },
+   "database":{
+      "type":"string"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/enum.json b/application/Espo/Resources/metadata/fields/enum.json
index 056f52b724..cbd7aaa78a 100644
--- a/application/Espo/Resources/metadata/fields/enum.json
+++ b/application/Espo/Resources/metadata/fields/enum.json
@@ -21,5 +21,8 @@
    "search":{
       "basic":false,
       "advanced":true
+   },
+   "database":{
+      "type":"string"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/enumInt.json b/application/Espo/Resources/metadata/fields/enumInt.json
index 59dab473ec..f9b91b256c 100644
--- a/application/Espo/Resources/metadata/fields/enumInt.json
+++ b/application/Espo/Resources/metadata/fields/enumInt.json
@@ -16,5 +16,8 @@
    "search":{
       "basic":false,
       "advanced":true
+   },
+   "database":{
+      "type":"integer"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/int.json b/application/Espo/Resources/metadata/fields/int.json
index 79bd06eab6..bd79f32114 100644
--- a/application/Espo/Resources/metadata/fields/int.json
+++ b/application/Espo/Resources/metadata/fields/int.json
@@ -21,5 +21,8 @@
    "search":{
       "basic":false,
       "advanced":true
+   },
+   "database":{
+      "type":"integer"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/multienum.json b/application/Espo/Resources/metadata/fields/multienum.json
index a98f0c50a0..e10385bf47 100644
--- a/application/Espo/Resources/metadata/fields/multienum.json
+++ b/application/Espo/Resources/metadata/fields/multienum.json
@@ -17,5 +17,8 @@
    "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 50ae45269d..d4e3bb2404 100644
--- a/application/Espo/Resources/metadata/fields/phone.json
+++ b/application/Espo/Resources/metadata/fields/phone.json
@@ -18,5 +18,8 @@
    "search":{
       "basic":true,
       "advanced":true
+   },
+   "database":{
+      "type":"string"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/url.json b/application/Espo/Resources/metadata/fields/url.json
index 8bf30f983a..6b4282ec99 100644
--- a/application/Espo/Resources/metadata/fields/url.json
+++ b/application/Espo/Resources/metadata/fields/url.json
@@ -17,5 +17,8 @@
    "search":{
       "basic":true,
       "advanced":true
+   },
+   "database":{
+      "type":"string"
    }
 }
diff --git a/application/Espo/Resources/metadata/fields/varchar.json b/application/Espo/Resources/metadata/fields/varchar.json
index 8bf30f983a..6b4282ec99 100644
--- a/application/Espo/Resources/metadata/fields/varchar.json
+++ b/application/Espo/Resources/metadata/fields/varchar.json
@@ -17,5 +17,8 @@
    "search":{
       "basic":true,
       "advanced":true
+   },
+   "database":{
+      "type":"string"
    }
 }
diff --git a/vendor/bin/doctrine b/vendor/bin/doctrine
deleted file mode 120000
index bb221732eb..0000000000
--- a/vendor/bin/doctrine
+++ /dev/null
@@ -1 +0,0 @@
-../doctrine/orm/bin/doctrine
\ No newline at end of file
diff --git a/vendor/bin/doctrine b/vendor/bin/doctrine
new file mode 100644
index 0000000000..c359ca7d83
--- /dev/null
+++ b/vendor/bin/doctrine
@@ -0,0 +1,4 @@
+#!/usr/bin/env php
+.
+ */
+
+use Symfony\Component\Console\Helper\HelperSet;
+use Doctrine\ORM\Tools\Console\ConsoleRunner;
+
+(@include_once __DIR__ . '/../vendor/autoload.php') || @include_once __DIR__ . '/../../../autoload.php';
+
+$directories = array(getcwd(), getcwd() . DIRECTORY_SEPARATOR . 'config');
+
+$configFile = null;
+foreach ($directories as $directory) {
+    $configFile = $directory . DIRECTORY_SEPARATOR . 'cli-config.php';
+
+    if (file_exists($configFile)) {
+        break;
+    }
+}
+
+if ( ! file_exists($configFile)) {
+    ConsoleRunner::printCliConfigTemplate();
+    exit(1);
+}
+
+if ( ! is_readable($configFile)) {
+    echo 'Configuration file [' . $configFile . '] does not have read permission.' . "\n";
+    exit(1);
+}
+
+$commands = array();
+
+$helperSet = require $configFile;
+
+if ( ! ($helperSet instanceof HelperSet)) {
+    foreach ($GLOBALS as $helperSetCandidate) {
+        if ($helperSetCandidate instanceof HelperSet) {
+            $helperSet = $helperSetCandidate;
+            break;
+        }
+    }
+}
+
+\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet, $commands);
diff --git a/vendor/bin/phpunit b/vendor/bin/phpunit
deleted file mode 120000
index d284b32d0c..0000000000
--- a/vendor/bin/phpunit
+++ /dev/null
@@ -1 +0,0 @@
-../phpunit/phpunit/composer/bin/phpunit
\ No newline at end of file
diff --git a/vendor/bin/phpunit b/vendor/bin/phpunit
new file mode 100644
index 0000000000..0c2f0b26aa
--- /dev/null
+++ b/vendor/bin/phpunit
@@ -0,0 +1,63 @@
+#!/usr/bin/env php
+.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *
+ *   * Neither the name of Sebastian Bergmann nor the names of his
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main');
+
+$files = array(
+  __DIR__ . '/../../vendor/autoload.php',
+  __DIR__ . '/../../../../autoload.php'
+);
+
+foreach ($files as $file) {
+    if (file_exists($file)) {
+        require $file;
+
+        define('PHPUNIT_COMPOSER_INSTALL', $file);
+
+        break;
+    }
+}
+
+if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
+    die(
+      'You need to set up the project dependencies using the following commands:' . PHP_EOL .
+      'curl -s http://getcomposer.org/installer | php' . PHP_EOL .
+      'php composer.phar install' . PHP_EOL
+    );
+}
+
+PHPUnit_TextUI_Command::main();