redefine doctrine DBAL classes

This commit is contained in:
Taras Machyshyn
2014-01-22 16:44:24 +02:00
parent 296c30d142
commit 2f70de2a32
11 changed files with 386 additions and 24 deletions
@@ -0,0 +1,13 @@
<?php
namespace Espo\Core\Utils\Database\DBAL\Driver\Mysqli;
class Driver extends \Doctrine\DBAL\Driver\Mysqli\Driver
{
public function getDatabasePlatform()
{
return new \Espo\Core\Utils\Database\DBAL\Platforms\MySqlPlatform();
}
}
@@ -0,0 +1,13 @@
<?php
namespace Espo\Core\Utils\Database\DBAL\Driver\PDOMySql;
class Driver extends \Doctrine\DBAL\Driver\PDOMySql\Driver
{
public function getDatabasePlatform()
{
return new \Espo\Core\Utils\Database\DBAL\Platforms\MySqlPlatform();
}
}
@@ -1,6 +1,6 @@
<?php
namespace Espo\Core\Utils\Database\FieldTypes;
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
@@ -1,6 +1,6 @@
<?php
namespace Espo\Core\Utils\Database\FieldTypes;
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
@@ -1,6 +1,6 @@
<?php
namespace Espo\Core\Utils\Database\FieldTypes;
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
@@ -1,6 +1,6 @@
<?php
namespace Espo\Core\Utils\Database\FieldTypes;
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
@@ -0,0 +1,252 @@
<?php
namespace Espo\Core\Utils\Database\DBAL\Platforms;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform
{
public function getAlterTableSQL(TableDiff $diff)
{
$columnSql = array();
$queryParts = array();
if ($diff->newName !== false) {
$queryParts[] = 'RENAME TO ' . $diff->newName;
}
foreach ($diff->addedColumns as $column) {
if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
continue;
}
$columnArray = $column->toArray();
$columnArray['comment'] = $this->getColumnComment($column);
$queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
}
foreach ($diff->removedColumns as $column) {
if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
continue;
}
//$queryParts[] = 'DROP ' . $column->getQuotedName($this); //espo: no needs to remove columns
}
foreach ($diff->changedColumns as $columnDiff) {
if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
continue;
}
/* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */
$column = $columnDiff->column;
$columnArray = $column->toArray();
$columnArray['comment'] = $this->getColumnComment($column);
$queryParts[] = 'CHANGE ' . ($columnDiff->oldColumnName) . ' '
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
}
//espo: It works not correctly. It can rename some existing fields
foreach ($diff->renamedColumns as $oldColumnName => $column) {
if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
continue;
}
$columnArray = $column->toArray();
$columnArray['comment'] = $this->getColumnComment($column);
/*$queryParts[] = 'CHANGE ' . $oldColumnName . ' '
. $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); */
$queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); //espo: fixed the problem
} //espo: END
$sql = array();
$tableSql = array();
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if (count($queryParts) > 0) {
$sql[] = 'ALTER TABLE ' . $this->espoQuote($diff->name) . ' ' . implode(", ", $queryParts);
}
$sql = array_merge(
$this->getPreAlterTableIndexForeignKeySQL($diff),
$sql,
$this->getPostAlterTableIndexForeignKeySQL($diff)
);
}
return array_merge($sql, $tableSql, $columnSql);
}
protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
{
$sql = array();
$table = $diff->name;
foreach ($diff->removedIndexes as $remKey => $remIndex) {
foreach ($diff->addedIndexes as $addKey => $addIndex) {
if ($remIndex->getColumns() == $addIndex->getColumns()) {
$type = '';
if ($addIndex->isUnique()) {
$type = 'UNIQUE ';
}
$query = 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP INDEX ' . $remIndex->getName() . ', ';
$query .= 'ADD ' . $type . 'INDEX ' . $addIndex->getName();
$query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex->getQuotedColumns($this)) . ')';
$sql[] = $query;
unset($diff->removedIndexes[$remKey]);
unset($diff->addedIndexes[$addKey]);
break;
}
}
}
$sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff));
return $sql;
}
public function getDropIndexSQL($index, $table=null)
{
if ($index instanceof Index) {
$indexName = $index->getQuotedName($this);
} else if(is_string($index)) {
$indexName = $index;
} else {
throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
} else if(!is_string($table)) {
throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
}
if ($index instanceof Index && $index->isPrimary()) {
// mysql primary keys are always named "PRIMARY",
// so we cannot use them in statements because of them being keyword.
return $this->getDropPrimaryKeySQL($table);
}
return 'DROP INDEX ' . $indexName . ' ON ' . $this->espoQuote($table);
}
protected function getDropPrimaryKeySQL($table)
{
return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP PRIMARY KEY';
}
public function getDropTemporaryTableSQL($table)
{
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
} else if(!is_string($table)) {
throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
}
return 'DROP TEMPORARY TABLE ' . $this->espoQuote($table);
}
//ESPO: fix problem with quoting table name
public function espoQuote($name)
{
if ($name instanceof Table) {
$name = $name->getQuotedName($this);
}
if (isset($name[0]) && $name[0] != '`') {
$name = $this->quoteIdentifier($name);
}
return $name;
}
public function getCreateForeignKeySQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey, $table)
{
$query = 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
return $query;
}
public function getIndexDeclarationSQL($name, Index $index)
{
$columns = $index->getQuotedColumns($this);
if (count($columns) === 0) {
throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
}
return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $this->espoQuote($name) . ' ('
. $this->getIndexFieldDeclarationListSQL($columns)
. ')';
}
public function getCreateIndexSQL(Index $index, $table)
{
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
$name = $index->getQuotedName($this);
$columns = $index->getQuotedColumns($this);
if (count($columns) == 0) {
throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
}
if ($index->isPrimary()) {
return $this->getCreatePrimaryKeySQL($index, $table);
}
$query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $this->espoQuote($table);
$query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')';
return $query;
}
public function getDropConstraintSQL($constraint, $table)
{
if ($constraint instanceof Constraint) {
$constraint = $constraint->getQuotedName($this);
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP CONSTRAINT ' . $constraint;
}
public function getDropForeignKeySQL($foreignKey, $table)
{
if ($foreignKey instanceof ForeignKeyConstraint) {
$foreignKey = $foreignKey->getQuotedName($this);
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
return 'ALTER TABLE ' . $this->espoQuote($table) . ' DROP FOREIGN KEY ' . $foreignKey;
}
public function getCreatePrimaryKeySQL(Index $index, $table)
{
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
return 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
}
//end: ESPO
}
@@ -0,0 +1,87 @@
<?php
namespace Espo\Core\Utils\Database\DBAL\Schema;
use Doctrine\DBAL\Schema\Column;
class Comparator extends \Doctrine\DBAL\Schema\Comparator
{
public function diffColumn(Column $column1, Column $column2)
{
$changedProperties = array();
if ( $column1->getType() != $column2->getType() ) {
//espo: fix problem with executing query for custom types
$column1DbTypeName = method_exists($column1->getType(), 'getDbTypeName') ? $column1->getType()->getDbTypeName() : $column1->getType()->getName();
$column2DbTypeName = method_exists($column2->getType(), 'getDbTypeName') ? $column2->getType()->getDbTypeName() : $column2->getType()->getName();
if (strtolower($column1DbTypeName) != strtolower($column2DbTypeName)) {
$changedProperties[] = 'type';
}
//END: espo
}
if ($column1->getNotnull() != $column2->getNotnull()) {
$changedProperties[] = 'notnull';
}
if ($column1->getDefault() != $column2->getDefault()) {
$changedProperties[] = 'default';
}
if ($column1->getUnsigned() != $column2->getUnsigned()) {
$changedProperties[] = 'unsigned';
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) {
// check if value of length is set at all, default value assumed otherwise.
$length1 = $column1->getLength() ?: 255;
$length2 = $column2->getLength() ?: 255;
if ($length1 != $length2) {
$changedProperties[] = 'length';
}
if ($column1->getFixed() != $column2->getFixed()) {
$changedProperties[] = 'fixed';
}
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) {
$changedProperties[] = 'precision';
}
if ($column1->getScale() != $column2->getScale()) {
$changedProperties[] = 'scale';
}
}
if ($column1->getAutoincrement() != $column2->getAutoincrement()) {
$changedProperties[] = 'autoincrement';
}
// only allow to delete comment if its set to '' not to null.
if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) {
$changedProperties[] = 'comment';
}
$options1 = $column1->getCustomSchemaOptions();
$options2 = $column2->getCustomSchemaOptions();
$commonKeys = array_keys(array_intersect_key($options1, $options2));
foreach ($commonKeys as $key) {
if ($options1[$key] !== $options2[$key]) {
$changedProperties[] = $key;
}
}
$diffKeys = array_keys(array_diff_key($options1, $options2) + array_diff_key($options2, $options1));
$changedProperties = array_merge($changedProperties, $diffKeys);
return $changedProperties;
}
}
@@ -11,7 +11,7 @@ class Converter
private $dbalSchema;
private $fileManager;
private $customTablePath = 'application/Espo/Core/Utils/Database/Schema/customTables';
private $customTablePath = 'application/Espo/Core/Utils/Database/Schema/CustomTables';
protected $typeList;
@@ -148,18 +148,7 @@ class Converter
if (!isset($tables[$tableName])) { //no needs to create the table if it already exists
$tables[$tableName] = $this->prepareManyMany($entityName, $relationParams, $tables);
}
break;
case 'hasMany':
if (isset($relationParams['relationName'])) {
$tableName = $relationParams['relationName'];
//check for duplication tables
if (!isset($tables[$tableName])) { //no needs to create the table if it already exists
$tables[$tableName] = $this->prepareManyMany($entityName, $relationParams, $tables);
}
}
break;
break;
case 'belongsTo':
$foreignEntity = $relationParams['entity'];
@@ -18,6 +18,16 @@ class Schema
private $connection;
protected $drivers = array(
'mysqli' => '\Espo\Core\Utils\Database\DBAL\Driver\Mysqli\Driver',
'pdo_mysql' => '\Espo\Core\Utils\Database\DBAL\Driver\PDOMySql\Driver',
);
protected $fieldTypePaths = array(
'Espo/Core/Utils/Database/DBAL/FieldTypes',
'Espo/Custom/Core/Utils/Database/DBAL/FieldTypes',
);
public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\File\Manager $fileManager)
{
@@ -25,7 +35,7 @@ class Schema
$this->metadata = $metadata;
$this->fileManager = $fileManager;
$this->comparator = new \Doctrine\DBAL\Schema\Comparator();
$this->comparator = new \Espo\Core\Utils\Database\DBAL\Schema\Comparator();
$this->initFieldTypes();
$this->converter = new \Espo\Core\Utils\Database\Converter($this->metadata, $this->fileManager);
@@ -72,6 +82,9 @@ class Schema
$dbalConfig = new \Doctrine\DBAL\Configuration();
$connectionParams = (array) $this->getConfig()->get('database');
$connectionParams['driverClass'] = $this->drivers[ $connectionParams['driver'] ];
unset($connectionParams['driver']);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $dbalConfig);
@@ -81,12 +94,7 @@ class Schema
protected function initFieldTypes()
{
$typePaths = array(
'Espo/Core/Utils/Database/FieldTypes',
'Espo/Custom/Core/Utils/Database/FieldTypes',
);
foreach($typePaths as $path) {
foreach($this->fieldTypePaths as $path) {
$typeList = $this->getFileManager()->getFileList('application/'.$path, false, '\.php$');
if ($typeList !== false) {