Completed
Pull Request — 2.0 (#62)
by
unknown
05:20
created

Projection   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 351
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 8
Bugs 2 Features 0
Metric Value
wmc 30
c 8
b 2
f 0
lcom 1
cbo 1
dl 0
loc 351
rs 10

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getIterator() 0 4 1
A getFlexibleEntityClass() 0 4 1
A __toString() 0 4 1
A __construct() 0 10 3
A unsetField() 0 7 1
A getFieldTypes() 0 12 3
A formatFieldsWithFieldAlias() 0 19 1
A replaceToken() 0 10 1
A setField() 0 11 2
A setFieldType() 0 6 1
A hasField() 0 4 1
A getFieldType() 0 6 2
A isArray() 0 4 1
A getFieldNames() 0 4 1
A getFieldWithTableAlias() 0 6 2
A getFieldsWithTableAlias() 0 11 3
A formatFields() 0 4 1
A checkField() 0 8 2
A checkFieldExist() 0 8 2
1
<?php
2
/*
3
 * This file is part of the PommProject/ModelManager package.
4
 *
5
 * (c) 2014 - 2015 Grégoire HUBERT <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PommProject\ModelManager\Model;
11
12
use PommProject\ModelManager\Exception\ModelException;
13
14
/**
15
 * Projection
16
 *
17
 * Define the content of SELECT or RETURNING (projection) statements.
18
 *
19
 * @package     ModelManager
20
 * @copyright   2014 - 2015 Grégoire HUBERT
21
 * @author      Grégoire HUBERT
22
 * @license     X11 {@link http://opensource.org/licenses/mit-license.php}
23
 */
24
class Projection implements \IteratorAggregate
25
{
26
    protected $flexible_entity_class;
27
    protected $fields = [];
28
    protected $types = [];
29
30
31
    /**
32
     * __construct
33
     *
34
     * @access public
35
     * @param  $flexible_entity_class
36
     * @param  array  $structure list of field names with types.
37
     */
38
    public function __construct($flexible_entity_class, array $structure = null)
39
    {
40
        $this->flexible_entity_class = $flexible_entity_class;
41
42
        if ($structure != null) {
43
            foreach ($structure as $field_name => $type) {
44
                $this->setField($field_name, sprintf("%%:%s:%%", $field_name), $type);
45
            }
46
        }
47
    }
48
49
    /**
50
     * getIterator
51
     *
52
     * This returns an ArrayIterator using the name => type association of the
53
     * projection.
54
     * @see IteratorAggregate
55
     *
56
     * @access public
57
     * @return \ArrayIterator
58
     */
59
    public function getIterator()
60
    {
61
        return new \ArrayIterator($this->types);
62
    }
63
64
    /**
65
     * getFlexibleEntityClass
66
     *
67
     * Get the flexible entity class associated with this projection.
68
     *
69
     * @access public
70
     * @return string
71
     */
72
    public function getFlexibleEntityClass()
73
    {
74
        return $this->flexible_entity_class;
75
    }
76
77
    /**
78
     * setField
79
     *
80
     * Set a field with a content. This override previous definition if exist.
81
     *
82
     * @access public
83
     * @param  string     $name
84
     * @param  string     $content
85
     * @param  string     $type    (null)
86
     * @throws \InvalidArgumentException if $name or $content is null
87
     * @return Projection $this
88
     */
89
    public function setField($name, $content, $type = null)
90
    {
91
        if ($content === null) {
92
            throw new \InvalidArgumentException(sprintf("Content cannot be null for field '%s'.", $name));
93
        }
94
95
        $this->checkField($name)->fields[$name] = $content;
96
        $this->types[$name] = $type;
97
98
        return $this;
99
    }
100
101
    /**
102
     * setFieldType
103
     *
104
     * Set or override a field type definition.
105
     *
106
     * @access public
107
     * @param  string     $name
108
     * @param  string     $type
109
     * @throws ModelException if name is null or does not exist.
110
     * @return Projection $this
111
     */
112
    public function setFieldType($name, $type)
113
    {
114
        $this->checkFieldExist($name)->types[$name] = $type;
115
116
        return $this;
117
    }
118
119
    /**
120
     * unsetField
121
     *
122
     * Unset an existing field
123
     *
124
     * @access public
125
     * @param  string     $name
126
     * @throws ModelException if field $name does not exist.
127
     * @return Projection $this
128
     */
129
    public function unsetField($name)
130
    {
131
        $this->checkFieldExist($name);
132
        unset($this->fields[$name], $this->types[$name]);
133
134
        return $this;
135
    }
136
137
    /**
138
     * hasField
139
     *
140
     * Return if the given field exist.
141
     *
142
     * @access public
143
     * @param  string  $name
144
     * @return boolean
145
     */
146
    public function hasField($name)
147
    {
148
        return isset($this->checkField($name)->fields[$name]);
149
    }
150
151
    /**
152
     * getFieldType
153
     *
154
     * Return the type associated with the given field.
155
     *
156
     * @access public
157
     * @param  string $name
158
     * @throws ModelException if $name is null or field does not exist
159
     * @return string null if type is not set
160
     */
161
    public function getFieldType($name)
162
    {
163
        return $this->checkFieldExist($name)->types[$name] != null
164
            ? rtrim($this->types[$name], '[]')
165
            : null;
166
    }
167
168
    /**
169
     * isArray
170
     *
171
     * Tel if a field is an array.
172
     *
173
     * @access public
174
     * @param  string $name
175
     * @throws ModelException if $name does not exist.
176
     * @throws \InvalidArgumentException if $name is null
177
     * @return bool
178
     */
179
    public function isArray($name)
180
    {
181
        return (bool) preg_match('/\[\]$/', $this->checkFieldExist($name)->types[$name]);
182
    }
183
184
    /**
185
     * getFieldNames
186
     *
187
     * Return fields names list.
188
     *
189
     * @access public
190
     * @return array fields list
191
     */
192
    public function getFieldNames()
193
    {
194
        return array_keys($this->fields);
195
    }
196
197
    /**
198
     * getFieldTypes
199
     *
200
     * Return an array with the known types.
201
     *
202
     * @access public
203
     * @return array
204
     */
205
    public function getFieldTypes()
206
    {
207
        $fields = [];
208
        foreach ($this->fields as $name => $value) {
209
            $fields[$name] = isset($this->types[$name])
210
                ? $this->types[$name]
211
                : null
212
                ;
213
        }
214
215
        return $fields;
216
    }
217
218
    /**
219
     * getFieldWithTableAlias
220
     *
221
     * Prepend the field name with alias if given.
222
     *
223
     * @access public
224
     * @param  string $name
225
     * @param  string $table_alias
226
     * @throws ModelException if $name does not exist.
227
     * @throws \InvalidArgumentException if $name is null
228
     * @return string
229
     */
230
    public function getFieldWithTableAlias($name, $table_alias = null)
231
    {
232
        $replace = $table_alias === null ? '' : sprintf("%s.", $table_alias);
233
234
        return $this->replaceToken($this->checkFieldExist($name)->fields[$name], $replace);
235
    }
236
237
    /**
238
     * getFieldsWithTableAlias
239
     *
240
     * Return the array of fields with table aliases expanded.
241
     *
242
     * @access public
243
     * @param  string $table_alias (null)
244
     * @return array
245
     */
246
    public function getFieldsWithTableAlias($table_alias = null)
247
    {
248
        $vals = [];
249
        $replace = $table_alias === null ? '' : sprintf("%s.", $table_alias);
250
251
        foreach ($this->fields as $name => $definition) {
252
            $vals[$name] = $this->replaceToken($this->fields[$name], $replace);
253
        }
254
255
        return $vals;
256
    }
257
258
    /**
259
     * formatFields
260
     *
261
     * Return a formatted string with fields like
262
     * a.field1, a.field2, ..., a.fieldN
263
     *
264
     * @access public
265
     * @param  string $table_alias
266
     * @return string
267
     */
268
    public function formatFields($table_alias = null)
269
    {
270
        return join(', ', $this->getFieldsWithTableAlias($table_alias));
271
    }
272
273
    /**
274
     * formatFieldsWithFieldAlias
275
     *
276
     * Return a formatted string with fields like
277
     * a.field1 AS field1, a.field2 AS fields2, ...
278
     *
279
     * @access public
280
     * @param  string $table_alias
281
     * @return string
282
     */
283
    public function formatFieldsWithFieldAlias($table_alias = null)
284
    {
285
        $fields = $this->getFieldsWithTableAlias($table_alias);
286
287
        return join(
288
            ', ',
289
            array_map(
290
                function ($field_alias, $field_definition) {
291
                    return sprintf(
292
                        '%s as "%s"',
293
                        $field_definition,
294
                        addcslashes($field_alias, '"\\')
295
                    );
296
                },
297
                array_keys($fields),
298
                $fields
299
            )
300
        );
301
    }
302
303
    /**
304
     * __toString
305
     *
306
     * String representation = formatFieldsWithFieldAlias().
307
     *
308
     * @access public
309
     * @return string
310
     */
311
    public function __toString()
312
    {
313
        return $this->formatFieldsWithFieldAlias();
314
    }
315
316
    /**
317
     * checkField
318
     *
319
     * Check if $name is not null
320
     *
321
     * @access private
322
     * @param  string     $name
323
     * @throws \InvalidArgumentException if name is null
324
     * @return Projection $this
325
     */
326
    private function checkField($name)
327
    {
328
        if ($name === null) {
329
            throw new \InvalidArgumentException(sprintf("Field name cannot be null."));
330
        }
331
332
        return $this;
333
    }
334
335
    /**
336
     * checkFieldExist
337
     *
338
     * Check if a field exist.
339
     *
340
     * @access private
341
     * @param  string     $name
342
     * @throws ModelException if field does not exist
343
     * @return Projection $this
344
     */
345
    private function checkFieldExist($name)
346
    {
347
        if (!$this->checkField($name)->hasField($name)) {
348
            throw new ModelException(sprintf("Field '%s' does not exist. Available fields are {%s}.", $name, join(', ', $this->getFieldNames())));
349
        }
350
351
        return $this;
352
    }
353
354
    /**
355
     * replaceToken
356
     *
357
     * Replace placeholders with their quoted names.
358
     *
359
     * @access protected
360
     * @param  string $string field definition
361
     * @param  string $prefix  optional unquoted prefix
362
     * @return string
363
     */
364
    protected function replaceToken($string, $prefix = '')
365
    {
366
        return preg_replace_callback(
367
            '/%:(\w.*):%/U',
368
            function (array $matches) use ($prefix) {
369
                return sprintf('%s"%s"', $prefix, addcslashes($matches[1], '"\\'));
370
            },
371
            $string
372
        );
373
    }
374
}
375