Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like SQLiteAdapter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SQLiteAdapter, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
42 | class SQLiteAdapter extends PdoAdapter implements AdapterInterface |
||
43 | { |
||
44 | protected $definitionsWithLimits = [ |
||
45 | 'CHARACTER', |
||
46 | 'VARCHAR', |
||
47 | 'VARYING CHARACTER', |
||
48 | 'NCHAR', |
||
49 | 'NATIVE CHARACTER', |
||
50 | 'NVARCHAR' |
||
51 | ]; |
||
52 | |||
53 | /** |
||
54 | * {@inheritdoc} |
||
55 | */ |
||
56 | 42 | public function connect() |
|
90 | |||
91 | /** |
||
92 | * {@inheritdoc} |
||
93 | */ |
||
94 | 48 | public function disconnect() |
|
98 | |||
99 | /** |
||
100 | * {@inheritdoc} |
||
101 | */ |
||
102 | public function hasTransactions() |
||
106 | |||
107 | /** |
||
108 | * {@inheritdoc} |
||
109 | */ |
||
110 | 1 | public function beginTransaction() |
|
114 | |||
115 | /** |
||
116 | * {@inheritdoc} |
||
117 | */ |
||
118 | public function commitTransaction() |
||
122 | |||
123 | /** |
||
124 | * {@inheritdoc} |
||
125 | */ |
||
126 | public function rollbackTransaction() |
||
130 | |||
131 | /** |
||
132 | * {@inheritdoc} |
||
133 | */ |
||
134 | 43 | public function quoteTableName($tableName) |
|
138 | |||
139 | /** |
||
140 | * {@inheritdoc} |
||
141 | */ |
||
142 | 44 | public function quoteColumnName($columnName) |
|
146 | |||
147 | /** |
||
148 | * {@inheritdoc} |
||
149 | */ |
||
150 | 42 | public function hasTable($tableName) |
|
160 | |||
161 | /** |
||
162 | * {@inheritdoc} |
||
163 | */ |
||
164 | 42 | public function createTable(Table $table) |
|
165 | { |
||
166 | // Add the default primary key |
||
167 | 42 | $columns = $table->getPendingColumns(); |
|
168 | 42 | $options = $table->getOptions(); |
|
169 | 42 | if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) { |
|
170 | 35 | $column = new Column(); |
|
171 | 35 | $column->setName('id') |
|
172 | 35 | ->setType('integer') |
|
173 | 35 | ->setIdentity(true); |
|
174 | |||
175 | 35 | array_unshift($columns, $column); |
|
176 | 42 | } elseif (isset($options['id']) && is_string($options['id'])) { |
|
177 | // Handle id => "field_name" to support AUTO_INCREMENT |
||
178 | 1 | $column = new Column(); |
|
179 | 1 | $column->setName($options['id']) |
|
180 | 1 | ->setType('integer') |
|
181 | 1 | ->setIdentity(true); |
|
182 | |||
183 | 1 | array_unshift($columns, $column); |
|
184 | 1 | } |
|
185 | |||
186 | $sql = 'CREATE TABLE '; |
||
187 | 42 | $sql .= $this->quoteTableName($table->getName()) . ' ('; |
|
188 | 42 | View Code Duplication | foreach ($columns as $column) { |
|
|||
189 | 42 | $sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', '; |
|
190 | 42 | } |
|
191 | 42 | ||
192 | // set the primary key(s) |
||
193 | View Code Duplication | if (isset($options['primary_key'])) { |
|
194 | 42 | $sql = rtrim($sql); |
|
195 | 42 | $sql .= ' PRIMARY KEY ('; |
|
196 | 42 | if (is_string($options['primary_key'])) { // handle primary_key => 'id' |
|
197 | 42 | $sql .= $this->quoteColumnName($options['primary_key']); |
|
198 | 42 | } elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id') |
|
199 | 42 | $sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key'])); |
|
200 | } |
||
201 | $sql .= ')'; |
||
202 | 1 | } else { |
|
203 | 1 | $sql = substr(rtrim($sql), 0, -1); // no primary keys |
|
204 | 1 | } |
|
205 | |||
206 | 1 | // set the foreign keys |
|
207 | 1 | $foreignKeys = $table->getForeignKeys(); |
|
208 | 1 | if (!empty($foreignKeys)) { |
|
209 | 1 | foreach ($foreignKeys as $foreignKey) { |
|
210 | 1 | $sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey); |
|
211 | 1 | } |
|
212 | 42 | } |
|
213 | 42 | ||
214 | 37 | $sql = rtrim($sql) . ');'; |
|
215 | // execute the sql |
||
216 | $this->execute($sql); |
||
217 | |||
218 | 42 | foreach ($table->getIndexes() as $index) { |
|
219 | 42 | $this->addIndex($table, $index); |
|
220 | 1 | } |
|
221 | 1 | } |
|
222 | 1 | ||
223 | 1 | /** |
|
224 | * {@inheritdoc} |
||
225 | 42 | */ |
|
226 | public function renameTable($tableName, $newTableName) |
||
230 | 6 | ||
231 | 42 | /** |
|
232 | 42 | * {@inheritdoc} |
|
233 | */ |
||
234 | public function dropTable($tableName) |
||
238 | |||
239 | 1 | /** |
|
240 | 1 | * {@inheritdoc} |
|
241 | */ |
||
242 | public function truncateTable($tableName) |
||
243 | { |
||
244 | $sql = sprintf( |
||
245 | 1 | 'DELETE FROM %s', |
|
246 | $this->quoteTableName($tableName) |
||
247 | 1 | ); |
|
248 | 1 | ||
249 | $this->execute($sql); |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | 1 | * {@inheritdoc} |
|
254 | */ |
||
255 | 1 | public function getColumns($tableName) |
|
280 | 1 | ||
281 | /** |
||
282 | 1 | * {@inheritdoc} |
|
283 | 1 | */ |
|
284 | 1 | View Code Duplication | public function hasColumn($tableName, $columnName) |
295 | 8 | ||
296 | /** |
||
297 | 8 | * {@inheritdoc} |
|
298 | 8 | */ |
|
299 | 8 | View Code Duplication | public function addColumn(Table $table, Column $column) |
310 | 4 | ||
311 | /** |
||
312 | 4 | * {@inheritdoc} |
|
313 | 4 | */ |
|
314 | 4 | public function renameColumn($tableName, $columnName, $newColumnName) |
|
364 | 1 | ||
365 | 1 | /** |
|
366 | 1 | * {@inheritdoc} |
|
367 | 1 | */ |
|
368 | 1 | public function changeColumn($tableName, $columnName, Column $newColumn) |
|
420 | 6 | ||
421 | /** |
||
422 | 6 | * {@inheritdoc} |
|
423 | 6 | */ |
|
424 | 6 | public function dropColumn($tableName, $columnName) |
|
481 | 2 | ||
482 | /** |
||
483 | 2 | * Get an array of indexes from a particular table. |
|
484 | 2 | * |
|
485 | 2 | * @param string $tableName Table Name |
|
486 | 2 | * @return array |
|
487 | 2 | */ |
|
488 | protected function getIndexes($tableName) |
||
505 | |||
506 | 9 | /** |
|
507 | 9 | * {@inheritdoc} |
|
508 | 9 | */ |
|
509 | 9 | View Code Duplication | public function hasIndex($tableName, $columns) |
527 | 9 | ||
528 | 9 | /** |
|
529 | * {@inheritdoc} |
||
530 | 9 | */ |
|
531 | 9 | View Code Duplication | public function hasIndexByName($tableName, $indexName) |
543 | 1 | ||
544 | /** |
||
545 | 1 | * {@inheritdoc} |
|
546 | */ |
||
547 | 1 | public function addIndex(Table $table, Index $index) |
|
563 | 8 | ||
564 | 8 | /** |
|
565 | 8 | * {@inheritdoc} |
|
566 | 8 | */ |
|
567 | 8 | public function dropIndex($tableName, $columns) |
|
590 | 1 | ||
591 | 1 | /** |
|
592 | 1 | * {@inheritdoc} |
|
593 | 1 | */ |
|
594 | 1 | View Code Duplication | public function dropIndexByName($tableName, $indexName) |
611 | 1 | ||
612 | 1 | /** |
|
613 | 1 | * {@inheritdoc} |
|
614 | 1 | */ |
|
615 | 1 | public function hasForeignKey($tableName, $columns, $constraint = null) |
|
629 | |||
630 | 5 | /** |
|
631 | * Get an array of foreign keys from a particular table. |
||
632 | 5 | * |
|
633 | 5 | * @param string $tableName Table Name |
|
634 | 5 | * @return array |
|
635 | */ |
||
636 | 1 | protected function getForeignKeys($tableName) |
|
667 | 5 | ||
668 | 5 | /** |
|
669 | 5 | * {@inheritdoc} |
|
670 | 5 | */ |
|
671 | 5 | public function addForeignKey(Table $table, ForeignKey $foreignKey) |
|
708 | 4 | ||
709 | 4 | /** |
|
710 | 4 | * {@inheritdoc} |
|
711 | 4 | */ |
|
712 | public function dropForeignKey($tableName, $columns, $constraint = null) |
||
769 | 1 | ||
770 | 1 | /** |
|
771 | * {@inheritdoc} |
||
772 | 1 | */ |
|
773 | public function insert(Table $table, $row) |
||
798 | |||
799 | /** |
||
800 | * {@inheritdoc} |
||
801 | */ |
||
802 | public function getSqlType($type, $limit = null) |
||
850 | 43 | ||
851 | 42 | /** |
|
852 | * Returns Phinx type by SQL type |
||
853 | 5 | * |
|
854 | * @param string $sqlTypeDef SQL type |
||
855 | 5 | * @returns string Phinx type |
|
856 | 4 | */ |
|
857 | public function getPhinxType($sqlTypeDef) |
||
858 | { |
||
859 | if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*$/', $sqlTypeDef, $matches)) { |
||
860 | 1 | throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported'); |
|
861 | 1 | } else { |
|
862 | $limit = null; |
||
863 | $precision = null; |
||
864 | 1 | $type = $matches[1]; |
|
865 | if (count($matches) > 2) { |
||
866 | $limit = $matches[3] ?: null; |
||
867 | 1 | } |
|
868 | if (count($matches) > 4) { |
||
869 | 1 | $precision = $matches[5]; |
|
870 | 1 | } |
|
871 | 1 | switch ($matches[1]) { |
|
872 | case 'varchar': |
||
873 | $type = static::PHINX_TYPE_STRING; |
||
874 | if ($limit === 255) { |
||
875 | $limit = null; |
||
876 | } |
||
877 | break; |
||
878 | View Code Duplication | case 'char': |
|
879 | $type = static::PHINX_TYPE_CHAR; |
||
880 | 3 | if ($limit === 255) { |
|
881 | $limit = null; |
||
882 | 3 | } |
|
883 | 1 | if ($limit === 36) { |
|
884 | $type = static::PHINX_TYPE_UUID; |
||
885 | 2 | } |
|
886 | 2 | break; |
|
887 | 2 | case 'int': |
|
888 | 2 | $type = static::PHINX_TYPE_INTEGER; |
|
889 | 1 | if ($limit === 11) { |
|
890 | 1 | $limit = null; |
|
891 | 2 | } |
|
892 | break; |
||
893 | case 'bigint': |
||
894 | 2 | if ($limit === 11) { |
|
895 | 2 | $limit = null; |
|
896 | 1 | } |
|
897 | 1 | $type = static::PHINX_TYPE_BIG_INTEGER; |
|
898 | break; |
||
899 | case 'blob': |
||
900 | 1 | $type = static::PHINX_TYPE_BINARY; |
|
901 | 2 | break; |
|
902 | } |
||
903 | View Code Duplication | if ($type === 'tinyint') { |
|
904 | if ($matches[3] === 1) { |
||
905 | $type = static::PHINX_TYPE_BOOLEAN; |
||
906 | $limit = null; |
||
907 | } |
||
908 | } |
||
909 | |||
910 | 2 | $this->getSqlType($type); |
|
911 | |||
912 | return [ |
||
913 | 'name' => $type, |
||
914 | 'limit' => $limit, |
||
915 | 'precision' => $precision |
||
916 | 2 | ]; |
|
917 | 1 | } |
|
918 | } |
||
919 | |||
920 | 1 | /** |
|
921 | 1 | * {@inheritdoc} |
|
922 | 2 | */ |
|
923 | 1 | public function createDatabase($name, $options = []) |
|
927 | |||
928 | /** |
||
929 | * {@inheritdoc} |
||
930 | */ |
||
931 | public function hasDatabase($name) |
||
935 | |||
936 | 1 | /** |
|
937 | 1 | * {@inheritdoc} |
|
938 | */ |
||
939 | 1 | public function dropDatabase($name) |
|
945 | |||
946 | 48 | /** |
|
947 | * Gets the SQLite Column Definition for a Column object. |
||
948 | 48 | * |
|
949 | 48 | * @param \Phinx\Db\Table\Column $column Column |
|
950 | * @return string |
||
951 | */ |
||
952 | protected function getColumnSqlDefinition(Column $column) |
||
987 | |||
988 | /** |
||
989 | * Gets the comment Definition for a Column object. |
||
990 | * |
||
991 | 42 | * @param \Phinx\Db\Table\Column $column Column |
|
992 | * @return string |
||
993 | 42 | */ |
|
994 | 42 | protected function getCommentDefinition(Column $column) |
|
1002 | 42 | ||
1003 | 42 | /** |
|
1004 | 4 | * Gets the SQLite Index Definition for an Index object. |
|
1005 | 4 | * |
|
1006 | * @param \Phinx\Db\Table $table Table |
||
1007 | 42 | * @param \Phinx\Db\Table\Index $index Index |
|
1008 | * @return string |
||
1009 | 42 | */ |
|
1010 | 42 | protected function getIndexSqlDefinition(Table $table, Index $index) |
|
1030 | 42 | ||
1031 | 2 | /** |
|
1032 | * {@inheritdoc} |
||
1033 | 42 | */ |
|
1034 | public function getColumnTypes() |
||
1035 | { |
||
1036 | return array_merge(parent::getColumnTypes(), ['enum']); |
||
1037 | } |
||
1038 | |||
1039 | /** |
||
1040 | * Gets the SQLite Foreign Key Definition for an ForeignKey object. |
||
1041 | * |
||
1042 | 8 | * @param \Phinx\Db\Table\ForeignKey $foreignKey |
|
1043 | * @return string |
||
1044 | 8 | */ |
|
1045 | 2 | View Code Duplication | protected function getForeignKeySqlDefinition(ForeignKey $foreignKey) |
1071 | } |
||
1072 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.