Completed
Push — master ( 5b2327...bb4968 )
by grégoire
01:17 queued 10s
created

Projection::unsetFields()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
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
     * unsetField
139
     *
140
     * Unset multiple existing fields
141
     *
142
     * @access public
143
     * @param  array     $fields
144
     * @throws ModelException if one field of $fields does not exist.
145
     * @return Projection $this
146
     */
147
    public function unsetFields($fields)
148
    {
149
        foreach ($fields as $field) {
150
            $this->unsetField($field);
151
        }
152
153
        return $this;
154
    }
155
156
    /**
157
     * hasField
158
     *
159
     * Return if the given field exist.
160
     *
161
     * @access public
162
     * @param  string  $name
163
     * @return boolean
164
     */
165
    public function hasField($name)
166
    {
167
        return isset($this->checkField($name)->fields[$name]);
168
    }
169
170
    /**
171
     * getFieldType
172
     *
173
     * Return the type associated with the given field.
174
     *
175
     * @access public
176
     * @param  string $name
177
     * @throws ModelException if $name is null or field does not exist
178
     * @return string null if type is not set
179
     */
180
    public function getFieldType($name)
181
    {
182
        return $this->checkFieldExist($name)->types[$name] != null
183
            ? rtrim($this->types[$name], '[]')
184
            : null;
185
    }
186
187
    /**
188
     * isArray
189
     *
190
     * Tel if a field is an array.
191
     *
192
     * @access public
193
     * @param  string $name
194
     * @throws ModelException if $name does not exist.
195
     * @throws \InvalidArgumentException if $name is null
196
     * @return bool
197
     */
198
    public function isArray($name)
199
    {
200
        return (bool) preg_match('/\[\]$/', $this->checkFieldExist($name)->types[$name]);
201
    }
202
203
    /**
204
     * getFieldNames
205
     *
206
     * Return fields names list.
207
     *
208
     * @access public
209
     * @return array fields list
210
     */
211
    public function getFieldNames()
212
    {
213
        return array_keys($this->fields);
214
    }
215
216
    /**
217
     * getFieldTypes
218
     *
219
     * Return an array with the known types.
220
     *
221
     * @access public
222
     * @return array
223
     */
224
    public function getFieldTypes()
225
    {
226
        $fields = [];
227
        foreach ($this->fields as $name => $value) {
228
            $fields[$name] = isset($this->types[$name])
229
                ? $this->types[$name]
230
                : null
231
                ;
232
        }
233
234
        return $fields;
235
    }
236
237
    /**
238
     * getFieldWithTableAlias
239
     *
240
     * Prepend the field name with alias if given.
241
     *
242
     * @access public
243
     * @param  string $name
244
     * @param  string $table_alias
245
     * @throws ModelException if $name does not exist.
246
     * @throws \InvalidArgumentException if $name is null
247
     * @return string
248
     */
249
    public function getFieldWithTableAlias($name, $table_alias = null)
250
    {
251
        $replace = $table_alias === null ? '' : sprintf("%s.", $table_alias);
252
253
        return $this->replaceToken($this->checkFieldExist($name)->fields[$name], $replace);
254
    }
255
256
    /**
257
     * getFieldsWithTableAlias
258
     *
259
     * Return the array of fields with table aliases expanded.
260
     *
261
     * @access public
262
     * @param  string $table_alias (null)
263
     * @return array
264
     */
265
    public function getFieldsWithTableAlias($table_alias = null)
266
    {
267
        $vals = [];
268
        $replace = $table_alias === null ? '' : sprintf("%s.", $table_alias);
269
270
        foreach ($this->fields as $name => $definition) {
271
            $vals[$name] = $this->replaceToken($this->fields[$name], $replace);
272
        }
273
274
        return $vals;
275
    }
276
277
    /**
278
     * formatFields
279
     *
280
     * Return a formatted string with fields like
281
     * a.field1, a.field2, ..., a.fieldN
282
     *
283
     * @access public
284
     * @param  string $table_alias
285
     * @return string
286
     */
287
    public function formatFields($table_alias = null)
288
    {
289
        return join(', ', $this->getFieldsWithTableAlias($table_alias));
290
    }
291
292
    /**
293
     * formatFieldsWithFieldAlias
294
     *
295
     * Return a formatted string with fields like
296
     * a.field1 AS field1, a.field2 AS fields2, ...
297
     *
298
     * @access public
299
     * @param  string $table_alias
300
     * @return string
301
     */
302
    public function formatFieldsWithFieldAlias($table_alias = null)
303
    {
304
        $fields = $this->getFieldsWithTableAlias($table_alias);
305
306
        return join(
307
            ', ',
308
            array_map(
309
                function ($field_alias, $field_definition) {
310
                    return sprintf(
311
                        '%s as "%s"',
312
                        $field_definition,
313
                        addcslashes($field_alias, '"\\')
314
                    );
315
                },
316
                array_keys($fields),
317
                $fields
318
            )
319
        );
320
    }
321
322
    /**
323
     * __toString
324
     *
325
     * String representation = formatFieldsWithFieldAlias().
326
     *
327
     * @access public
328
     * @return string
329
     */
330
    public function __toString()
331
    {
332
        return $this->formatFieldsWithFieldAlias();
333
    }
334
335
    /**
336
     * checkField
337
     *
338
     * Check if $name is not null
339
     *
340
     * @access private
341
     * @param  string     $name
342
     * @throws \InvalidArgumentException if name is null
343
     * @return Projection $this
344
     */
345
    private function checkField($name)
346
    {
347
        if ($name === null) {
348
            throw new \InvalidArgumentException(sprintf("Field name cannot be null."));
349
        }
350
351
        return $this;
352
    }
353
354
    /**
355
     * checkFieldExist
356
     *
357
     * Check if a field exist.
358
     *
359
     * @access private
360
     * @param  string     $name
361
     * @throws ModelException if field does not exist
362
     * @return Projection $this
363
     */
364
    private function checkFieldExist($name)
365
    {
366
        if (!$this->checkField($name)->hasField($name)) {
367
            throw new ModelException(sprintf("Field '%s' does not exist. Available fields are {%s}.", $name, join(', ', $this->getFieldNames())));
368
        }
369
370
        return $this;
371
    }
372
373
    /**
374
     * replaceToken
375
     *
376
     * Replace placeholders with their quoted names.
377
     *
378
     * @access protected
379
     * @param  string $string field definition
380
     * @param  string $prefix  optional unquoted prefix
381
     * @return string
382
     */
383
    protected function replaceToken($string, $prefix = '')
384
    {
385
        return preg_replace_callback(
386
            '/%:(\w.*):%/U',
387
            function (array $matches) use ($prefix) {
388
                return sprintf('%s"%s"', $prefix, addcslashes($matches[1], '"\\'));
389
            },
390
            $string
391
        );
392
    }
393
}
394