Completed
Push — master ( 3d019e...3abb57 )
by Sébastien
25:13
created

PdoMysqlMetadataReader::readColumnsMetadata()   C

Complexity

Conditions 10
Paths 34

Size

Total Lines 80
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 10.562

Importance

Changes 0
Metric Value
dl 0
loc 80
ccs 37
cts 45
cp 0.8222
rs 5.5471
c 0
b 0
f 0
cc 10
eloc 39
nc 34
nop 1
crap 10.562

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Soluble\Metadata\Reader;
4
5
use Soluble\Metadata\ColumnsMetadata;
6
use Soluble\Metadata\Exception;
7
use Soluble\Datatype\Column;
8
use Soluble\Metadata\Reader\Mapping\PdoMysqlMapping;
9
use PDO;
10
11
class PdoMysqlMetadataReader extends AbstractMetadataReader
12
{
13
    /**
14
     * @var PDO
15
     */
16
    protected $pdo;
17
18
    /**
19
     * @param PDO $pdo
20
     *
21
     * @throws Exception\UnsupportedFeatureException
22
     * @throws Exception\UnsupportedDriverException
23
     */
24 12
    public function __construct(PDO $pdo)
25
    {
26 12
        $driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
27 12
        if (strtolower($driver) !== 'mysql') {
28 1
            throw new Exception\UnsupportedDriverException(__CLASS__ . " supports only pdo_mysql driver, '$driver' given.");
29
        }
30 12
        $this->pdo = $pdo;
31 12
    }
32
33
    /**
34
     * {@inheritdoc}
35
     *
36
     * @throws \Soluble\Metadata\Exception\ConnectionException
37
     * @throws \Soluble\Metadata\Exception\EmptyQueryException
38
     */
39 3
    protected function readColumnsMetadata($sql)
40
    {
41 3
        $metadata = new ColumnsMetadata();
42 3
        $fields = $this->readFields($sql);
43
44 2
        $type_map = PdoMysqlMapping::getDatatypeMapping();
45
46 2
        foreach ($fields as $idx => $field) {
47 2
            $name = $field['name'];
48 2
            $tableName = $field['table'];
49
50 2
            $type = strtoupper($field['native_type']);
51
52 2
            if (!$type_map->offsetExists($type)) {
53
                $msg = "Cannot get type for field '$name'. Mapping for native type [$type] cannot be resolved into a valid type for driver: " . __CLASS__;
54
                throw new Exception\UnsupportedTypeException($msg);
55
            }
56
57 2
            $datatype = $type_map->offsetGet($type);
58
59 2
            $column = Column\Type::createColumnDefinition($datatype['type'], $name, $tableName, $schemaName = null);
60 2
            $alias = $field['name'];
61
62 2
            $column->setAlias($alias);
63 2
            $column->setTableAlias($field['table']);
64
            //$column->setCatalog($field->catalog);
65 2
            $column->setOrdinalPosition($idx + 1);
66 2
            $column->setDataType($datatype['type']);
67 2
            $column->setIsNullable(!in_array('not_null', $field['flags'], true));
68 2
            $column->setIsPrimary(in_array('primary_key', $field['flags'], true));
69
            //$column->setColumnDefault($field->def);
70 2
            $column->setNativeDataType($datatype['native']);
71
72
            /*
73
              if ($column instanceof Column\Definition\NumericColumnInterface) {
74
              $column->setNumericUnsigned(($field->flags & MYSQLI_UNSIGNED_FLAG) > 0);
75
              }
76
77
              if ($column instanceof Column\Definition\IntegerColumn) {
78
              $column->setIsAutoIncrement(($field->flags & MYSQLI_AUTO_INCREMENT_FLAG) > 0);
79
              }
80
             */
81 2
            if ($column instanceof Column\Definition\DecimalColumn) {
82
                // salary DECIMAL(5,2)
83
                // In this example, 5 is the precision and 2 is the scale.
84
                // Standard SQL requires that DECIMAL(5,2) be able to store any value
85
                // with five digits and two decimals, so values that can be stored in
86
                // the salary column range from -999.99 to 999.99.
87
88 1
                $column->setNumericUnsigned(false);
89 1
                $column->setNumericPrecision($field['precision']);
90 1
                $column->setNumericScale($field['len'] - $field['precision'] + 1);
91 1
            }
92
93 2
            if ($column instanceof Column\Definition\StringColumn) {
94 2
                $column->setCharacterMaximumLength($field['len']);
95 2
            }
96
97 2
            if ($column instanceof Column\Definition\BlobColumn) {
98
                $column->setCharacterOctetLength($field['len']);
99
            }
100
101 2
            if ($metadata->offsetExists($alias)) {
102 1
                $prev_column = $metadata->offsetGet($alias);
103 1
                $prev_def = $prev_column->toArray();
104 1
                $curr_def = $column->toArray();
105 1
                if ($prev_def['dataType'] !== $curr_def['dataType'] || $prev_def['nativeDataType'] !== $curr_def['nativeDataType']) {
106 1
                    throw new Exception\AmbiguousColumnException("Cannot get column metadata, non unique column found '$alias' in query with different definitions.");
107
                }
108
109
                // If the the previous definition, was a prev_def
110
                if ($prev_def['isPrimary']) {
111
                    $column = $prev_column;
112
                }
113
            }
114 2
            $metadata->offsetSet($alias, $column);
115 2
        }
116
117 1
        return $metadata;
118
    }
119
120
    /**
121
     * Read fields from pdo source.
122
     *
123
     * @throws Exception\ConnectionException
124
     *
125
     * @param string $sql
126
     *
127
     * @return array
128
     *
129
     * @throws \Soluble\Metadata\Exception\EmptyQueryException
130
     */
131 3
    protected function readFields($sql)
132
    {
133 3
        if (trim($sql) === '') {
134 1
            throw new Exception\EmptyQueryException('Cannot read fields for an empty query');
135
        }
136
137 2
        $sql = $this->getEmptiedQuery($sql);
138
139 2
        $stmt = $this->pdo->prepare($sql);
140 2
        $stmt->execute();
141 2
        $column_count = $stmt->columnCount();
142 2
        $metaFields = [];
143 2
        for ($i = 0; $i < $column_count; ++$i) {
144 2
            $meta = $stmt->getColumnMeta($i);
145 2
            $metaFields[$i] = $meta;
146 2
        }
147
148 2
        $stmt->closeCursor();
149 2
        unset($stmt);
150
151 2
        return $metaFields;
152
    }
153
}
154