Completed
Push — master ( 3abb57...f20526 )
by Sébastien
02:03 queued 36s
created

PdoMysqlMetadataReader::readColumnsMetadata()   C

Complexity

Conditions 10
Paths 34

Size

Total Lines 80
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 10.2368

Importance

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

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