Completed
Pull Request — master (#6563)
by Joas
14:47
created

OCPostgreSqlPlatform::shouldSkipDropDefault()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 9
nc 6
nop 1
dl 0
loc 10
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2017, ownCloud GmbH
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OC\DB;
23
24
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
25
use Doctrine\DBAL\Schema\ColumnDiff;
26
use Doctrine\DBAL\Schema\TableDiff;
27
use Doctrine\DBAL\Types\Type;
28
29
class OCPostgreSqlPlatform extends PostgreSqlPlatform {
30
31
	/**
32
	 * {@inheritDoc}
33
	 */
34
	public function getAlterTableSQL(TableDiff $diff){
35
		$queries = parent::getAlterTableSQL($diff);
36
		foreach ($queries as $index => $sql){
37
			// BIGSERIAL could not be used in statements altering column type
38
			// That's why we replace it with BIGINT 
39
			// see https://github.com/owncloud/core/pull/28364#issuecomment-315006853
40
			if (preg_match('|(ALTER TABLE\s+\S+\s+ALTER\s+\S+\s+TYPE\s+)(BIGSERIAL)|i', $sql, $matches)) {
41
				$alterTable = $matches[1];
42
				$queries[$index] = $alterTable . 'BIGINT';
43
			}
44
45
			// Changing integer to bigint kills next autoincrement value
46
			// see https://github.com/owncloud/core/pull/28364#issuecomment-315006853
47
			if (preg_match('|ALTER TABLE\s+(\S+)\s+ALTER\s+(\S+)\s+DROP DEFAULT|i', $sql, $matches)) {
48
				$queryColumnName = $matches[2];
49
				$columnDiff = $this->findColumnDiffByName($diff, $queryColumnName);
50
				if ($columnDiff && $this->shouldSkipDropDefault($columnDiff)) {
51
					unset($queries[$index]);
52
					continue;
53
				}
54
			}
55
		}
56
		
57
		return $queries;
58
	}
59
60
	/**
61
	 * We should NOT drop next sequence value if
62
	 * - type was changed from INTEGER to BIGINT
63
	 * - column keeps an autoincrement
64
	 * - default value is kept NULL
65
	 *
66
	 * @param ColumnDiff $columnDiff
67
	 * @return bool
68
	 */
69
	private function shouldSkipDropDefault(ColumnDiff $columnDiff) {
70
		$column = $columnDiff->column;
71
		$fromColumn = $columnDiff->fromColumn;
72
		return $fromColumn->getType()->getName() === Type::INTEGER
73
				&& $column->getType()->getName() === Type::BIGINT
74
				&& $fromColumn->getDefault() === null
75
				&& $column->getDefault() === null
76
				&& $fromColumn->getAutoincrement()
77
				&& $column->getAutoincrement();
78
	}
79
80
	/**
81
	 * @param TableDiff $diff
82
	 * @param string $name
83
	 * @return  ColumnDiff | false
84
	 */
85
	private function findColumnDiffByName(TableDiff $diff, $name) {
86
		foreach ($diff->changedColumns as $columnDiff) {
87
			$oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($this);
88
			if ($oldColumnName === $name) {
89
				return $columnDiff;
90
			}
91
		}
92
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\DB\OCPostgreSqlPlatform::findColumnDiffByName of type Doctrine\DBAL\Schema\ColumnDiff.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
93
	}
94
}
95