Completed
Push — master ( 6bd930...6adfd5 )
by Rasmus
02:26
created

ReturnVars::addColumns()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
ccs 13
cts 13
cp 1
rs 8.439
cc 6
eloc 12
nc 18
nop 1
crap 6
1
<?php
2
3
namespace mindplay\sql\model\components;
4
5
use mindplay\sql\framework\Driver;
6
use mindplay\sql\framework\mappers\TypeMapper;
7
use mindplay\sql\framework\TypeProvider;
8
use mindplay\sql\model\Column;
9
use mindplay\sql\model\Table;
10
use mindplay\sql\model\Type;
11
use OutOfBoundsException;
12
13
/**
14
 * This component implements support for return variable expressions (for use in a SELECT or RETURNING clause)
15
 */
16
class ReturnVars
17
{
18
    /**
19
     * @var string[] list of return variable expressions (for use in a SELECT or RETURNING clause)
20
     */
21
    private $vars = [];
22
23
    /**
24
     * @var Type[] map where return variable name maps to Type
25
     */
26
    private $type_map = [];
27
28
    /**
29
     * @var Table
30
     */
31
    private $root;
32
33
    /**
34
     * @var Driver
35
     */
36
    private $driver;
37
38
    /**
39
     * @var TypeProvider
40
     */
41
    private $types;
42
    
43
    /**
44
     * @param Table        $root
45
     * @param Driver       $driver
46
     * @param TypeProvider $types
47
     */
48 1
    public function __construct(Table $root, Driver $driver, TypeProvider $types)
49
    {
50 1
        $this->root = $root;
51 1
        $this->driver = $driver;
52 1
        $this->types = $types;
53 1
    }
54
55
    /**
56
     * Add all the Columns of a full Table to be selected and returned
57
     *
58
     * @param Table $table Table to select and return
59
     */
60 1
    public function addTable(Table $table)
61
    {
62 1
        $this->vars[] = "{$table}.*";
63
64 1
        $this->type_map = array_merge($this->type_map, $this->createTypeMap($table));
65 1
    }
66
67
    /**
68
     * Add one or more Columns to select and return
69
     *
70
     * @param Column|Column[] one or more Columns to select and return
71
     */
72 1
    public function addColumns($cols)
73
    {
74
        /**
75
         * @var Column[] $cols
76
         */
77
78 1
        $cols = is_array($cols) ? $cols : [$cols];
79
80 1
        foreach ($cols as $col) {
81 1
            $alias = $col->getAlias();
82
83 1
            $col_name = $alias ?: $col->getName();
84
85 1
            $table = $col->getTable();
86
87 1
            $table_name = $table->getAlias() ?: $table->getName();
88
89 1
            $column_expr = $this->driver->quoteName($table_name) . '.' . $this->driver->quoteName($col->getName());
90
91 1
            $this->vars[$col_name] = $alias
92 1
                ? "{$column_expr} AS " . $this->driver->quoteName($col_name)
93 1
                : "{$column_expr}";
94
95 1
            $this->type_map[$col_name] = $col->getType();
96
        }
97 1
    }
98
99
    /**
100
     * Add an SQL expression to select and return
101
     *
102
     * @param string           $expr return expression
103
     * @param string|null      $name return variable name (optional, but usually required)
104
     * @param Type|string|null $type optional Type (or Type class-name)
105
     */
106 1
    public function addValue($expr, $name = null, $type = null)
107
    {
108 1
        if (isset($this->vars[$name])) {
109
            throw new OutOfBoundsException("duplicate return variable name: {$name}");
110
        }
111
112 1
        if ($name === null) {
113 1
            $this->vars[] = "{$expr}";
114
        } else {
115 1
            $quoted_name = $this->driver->quoteName($name);
116
117 1
            $this->vars[$name] = "{$expr} AS {$quoted_name}";
118
119 1
            if ($type !== null) {
120 1
                $this->type_map[$name] = is_string($type)
121 1
                    ? $this->types->getType($type)
122
                    : $type; // assumes Type instance
123
            }
124
        }
125 1
    }
126
127
    /**
128
     * @return TypeMapper
129
     */
130 1
    public function createTypeMapper()
131
    {
132 1
        $type_map = $this->type_map;
133
134 1
        if (count($this->vars) === 0) {
135
            // no defined return vars - buildReturnVars() will auto-select the root node, so
136
            // we need to add root Column Types to the TypeMapper we're creating here:
137
138 1
            $type_map = array_merge($this->createTypeMap($this->root), $type_map);
139
        }
140
141 1
        return new TypeMapper($type_map);
142
    }
143
    
144
    /**
145
     * @return string comma-separated return expressions (for use in the SELECT or RETURNING clause of an SQL query)
146
     */
147 1
    public function buildReturnVars()
148
    {
149 1
        $return_vars = $this->vars;
150
151 1
        if (count($return_vars) === 0) {
152
            // no defined return vars - getMappers() will create a Type-map for the root node,
153
            // so we need to auto-select the root node here:
154
155 1
            $return_vars[] = "{$this->root}.*";
156
        }
157
158 1
        return implode(",\n  ", $return_vars);
159
    }
160
161
    /**
162
     * Internally creates a full Type-map for all Columns in a given Table
163
     *
164
     * @param Table $table
165
     *
166
     * @return Type[] map where Column Alias maps to Type
167
     */
168 1
    private function createTypeMap(Table $table)
169
    {
170 1
        $type_map = [];
171
172 1
        foreach ($table->listColumns() as $column) {
173 1
            $type_map[$column->getAlias() ?: $column->getName()] = $column->getType();
174
        }
175
176 1
        return $type_map;
177
    }
178
}
179