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

WriteQueries::updateByPk()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 35
Code Lines 21

Duplication

Lines 7
Ratio 20 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
dl 7
loc 35
c 4
b 0
f 1
rs 8.8571
cc 3
eloc 21
nc 4
nop 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\ModelTrait;
11
12
use PommProject\Foundation\Where;
13
use PommProject\ModelManager\Exception\ModelException;
14
use PommProject\ModelManager\Model\CollectionIterator;
15
use PommProject\ModelManager\Model\FlexibleEntity\FlexibleEntityInterface;
16
use PommProject\ModelManager\Model\Model;
17
18
/**
19
 * WriteQueries
20
 *
21
 * Basic write queries for model instances.
22
 *
23
 * @package   ModelManager
24
 * @copyright 2014 - 2015 Grégoire HUBERT
25
 * @author    Grégoire HUBERT
26
 * @license   X11 {@link http://opensource.org/licenses/mit-license.php}
27
 */
28
trait WriteQueries
29
{
30
    use ReadQueries;
31
32
    /**
33
     * insertOne
34
     *
35
     * Insert a new entity in the database. The entity is passed by reference.
36
     * It is updated with values returned by the database (ie, default values).
37
     *
38
     * @access public
39
     * @param  FlexibleEntityInterface  $entity
40
     * @return Model                    $this
41
     */
42
    public function insertOne(FlexibleEntityInterface &$entity)
43
    {
44
        $values = $entity->fields(
45
            array_intersect(
46
                array_keys($this->getStructure()->getDefinition()),
47
                array_keys($entity->extract())
48
            )
49
        );
50
        $sql = strtr(
51
            "insert into :relation (:fields) values (:values) returning :projection",
52
            [
53
                ':relation'   => $this->getStructure()->getRelation(),
54
                ':fields'     => $this->getEscapedFieldList(array_keys($values)),
55
                ':projection' => $this->createProjection()->formatFieldsWithFieldAlias(),
56
                ':values'     => join(',', $this->getParametersList($values))
57
            ]);
58
59
        $entity = $this
0 ignored issues
show
Bug introduced by
The method status cannot be called on $this->query($sql, array...es($values))->current() (of type array|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
60
            ->query($sql, array_values($values))
61
            ->current()
62
            ->status(FlexibleEntityInterface::STATUS_EXIST);
63
64
        return $this;
65
    }
66
67
    /**
68
     * updateOne
69
     *
70
     * Update the entity. ONLY the fields indicated in the $fields array are
71
     * updated. The entity is passed by reference and its values are updated
72
     * with the values from the database. This means all changes not updated
73
     * are lost. The update is made upon a condition on the primary key. If the
74
     * primary key is not fully set, an exception is thrown.
75
     *
76
     * @access public
77
     * @param  FlexibleEntityInterface  $entity
78
     * @param  array                    $fields
79
     * @return Model                    $this
80
     */
81
    public function updateOne(FlexibleEntityInterface &$entity, array $fields)
82
    {
83
        $entity = $this->updateByPk(
84
            $entity->fields($this->getStructure()->getPrimaryKey()),
85
            $entity->fields($fields)
86
        );
87
88
        return $this;
89
    }
90
91
    /**
92
     * updateByPk
93
     *
94
     * Update a record and fetch it with its new values. If no records match
95
     * the given key, null is returned.
96
     *
97
     * @access public
98
     * @param  array          $primary_key
99
     * @param  array          $updates
100
     * @throws ModelException
101
     * @return FlexibleEntityInterface
102
     */
103
    public function updateByPk(array $primary_key, array $updates)
104
    {
105
        $where = $this
106
            ->checkPrimaryKey($primary_key)
107
            ->getWhereFrom($primary_key)
108
            ;
109
        $parameters = $this->getParametersList($updates);
110
        $update_strings = [];
111
112 View Code Duplication
        foreach ($updates as $field_name => $new_value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
            $update_strings[] = sprintf(
114
                "%s = %s",
115
                $this->escapeIdentifier($field_name),
116
                $parameters[$field_name]
117
            );
118
        }
119
120
        $sql = strtr(
121
            "update :relation set :update where :condition returning :projection",
122
            [
123
                ':relation'   => $this->getStructure()->getRelation(),
124
                ':update'     => join(', ', $update_strings),
125
                ':condition'  => (string) $where,
126
                ':projection' => $this->createProjection()->formatFieldsWithFieldAlias(),
127
            ]
128
        );
129
130
        $iterator = $this->query($sql, array_merge(array_values($updates), $where->getValues()));
131
132
        if ($iterator->isEmpty()) {
133
            return null;
134
        }
135
136
        return $iterator->current()->status(FlexibleEntityInterface::STATUS_EXIST);
0 ignored issues
show
Bug introduced by
The method status cannot be called on $iterator->current() (of type array|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
137
    }
138
139
    /**
140
     * updateWhere
141
     *
142
     * Update records by a given condition. A collection of all deleted entries is returned.
143
     *
144
     * @param        $where
145
     * @param  array $values
146
     * @param  array $updates
147
     * @return Model $this
148
     */
149
    public function updateWhere($where, array $values = [], array $updates)
150
    {
151
        if (!$where instanceof Where) {
152
            $where = new Where($where, $values);
153
        }
154
155
        $parameters = $this->getParametersList($updates);
156
        $update_strings = [];
157
158 View Code Duplication
        foreach ($updates as $field_name => $new_value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
159
            $update_strings[] = sprintf(
160
                "%s = %s",
161
                $this->escapeIdentifier($field_name),
162
                $parameters[$field_name]
163
            );
164
        }
165
166
        $sql = strtr(
167
            "update :relation set :update where :condition returning :projection",
168
            [
169
                ':relation'   => $this->getStructure()->getRelation(),
170
                ':update'     => join(', ', $update_strings),
171
                ':condition'  => (string) $where,
172
                ':projection' => $this->createProjection()->formatFieldsWithFieldAlias(),
173
            ]
174
        );
175
176
        $entity = $this->query($sql, array_merge(array_values($updates), $where->getValues()));
0 ignored issues
show
Unused Code introduced by
$entity is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
177
178
        return $this;
179
    }
180
181
    /**
182
     * deleteOne
183
     *
184
     * Delete an entity from a table. Entity is passed by reference and is
185
     * updated with the values fetched from the deleted record.
186
     *
187
     * @access public
188
     * @param  FlexibleEntityInterface  $entity
189
     * @return Model                    $this
190
     */
191
    public function deleteOne(FlexibleEntityInterface &$entity)
192
    {
193
        $entity = $this->deleteByPK($entity->fields($this->getStructure()->getPrimaryKey()));
194
195
        return $this;
196
    }
197
198
    /**
199
     * deleteByPK
200
     *
201
     * Delete a record from its primary key. The deleted entity is returned or
202
     * null if not found.
203
     *
204
     * @access public
205
     * @param  array          $primary_key
206
     * @throws ModelException
207
     * @return FlexibleEntityInterface
208
     */
209
    public function deleteByPK(array $primary_key)
210
    {
211
        $where = $this
212
            ->checkPrimaryKey($primary_key)
213
            ->getWhereFrom($primary_key)
214
        ;
215
216
        return $this->deleteWhere($where)->current();
217
    }
218
219
    /**
220
     * deleteWhere
221
     *
222
     * Delete records by a given condition. A collection of all deleted entries is returned.
223
     *
224
     * @param        $where
225
     * @param  array $values
226
     * @return CollectionIterator
227
     */
228
    public function deleteWhere($where, array $values = [])
229
    {
230
        if (!$where instanceof Where) {
231
            $where = new Where($where, $values);
232
        }
233
234
        $sql = strtr(
235
            "delete from :relation where :condition returning :projection",
236
            [
237
                ':relation'   => $this->getStructure()->getRelation(),
238
                ':condition'  => (string) $where,
239
                ':projection' => $this->createProjection()->formatFieldsWithFieldAlias(),
240
            ]
241
        );
242
243
        $collection = $this->query($sql, $where->getValues());
244
        foreach ($collection as $entity) {
245
            $entity->status(FlexibleEntityInterface::STATUS_NONE);
0 ignored issues
show
Bug introduced by
The method status cannot be called on $entity (of type array|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
246
        }
247
        $collection->rewind();
248
249
        return $collection;
250
    }
251
252
    /**
253
     * createAndSave
254
     *
255
     * Create a new entity from given values and save it in the database.
256
     *
257
     * @access public
258
     * @param  array          $values
259
     * @return FlexibleEntityInterface
260
     */
261
    public function createAndSave(array $values)
262
    {
263
        $entity = $this->createEntity($values);
264
        $this->insertOne($entity);
265
266
        return $entity;
267
    }
268
269
    /**
270
     * getEscapedFieldList
271
     *
272
     * Return a comma separated list with the given escaped field names.
273
     *
274
     * @access protected
275
     * @param  array  $fields
276
     * @return string
277
     */
278
    public function getEscapedFieldList(array $fields)
279
    {
280
        return join(
281
            ', ',
282
            array_map(
283
                function ($field) { return $this->escapeIdentifier($field); },
284
                $fields
285
            ));
286
    }
287
288
    /**
289
     * getParametersList
290
     *
291
     * Create a parameters list from values.
292
     *
293
     * @access protected
294
     * @param  array    $values
295
     * @return array    $escape codes
296
     */
297
    protected function getParametersList(array $values)
298
    {
299
        $parameters = [];
300
301
        foreach ($values as $name => $value) {
302
            $parameters[$name] = sprintf(
303
                "$*::%s",
304
                $this->getStructure()->getTypeFor($name)
305
            );
306
        }
307
308
        return $parameters;
309
    }
310
}
311