WriteQueries::updateByPk()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 9.36
c 0
b 0
f 0
cc 3
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
        if (empty($fields)) {
84
            $fields = $entity->getModifiedColumns();
85
        }
86
87
        $entity = $this->updateByPk(
88
            $entity->fields($this->getStructure()->getPrimaryKey()),
89
            $entity->fields($fields)
90
        );
91
92
        return $this;
93
    }
94
95
    /**
96
     * updateByPk
97
     *
98
     * Update a record and fetch it with its new values. If no records match
99
     * the given key, null is returned.
100
     *
101
     * @access public
102
     * @param  array          $primary_key
103
     * @param  array          $updates
104
     * @throws ModelException
105
     * @return FlexibleEntityInterface
106
     */
107
    public function updateByPk(array $primary_key, array $updates)
108
    {
109
        $where = $this
110
            ->checkPrimaryKey($primary_key)
111
            ->getWhereFrom($primary_key)
112
            ;
113
        $parameters = $this->getParametersList($updates);
114
        $update_strings = [];
115
116
        foreach ($updates as $field_name => $new_value) {
117
            $update_strings[] = sprintf(
118
                "%s = %s",
119
                $this->escapeIdentifier($field_name),
120
                $parameters[$field_name]
121
            );
122
        }
123
124
        $sql = strtr(
125
            "update :relation set :update where :condition returning :projection",
126
            [
127
                ':relation'   => $this->getStructure()->getRelation(),
128
                ':update'     => join(', ', $update_strings),
129
                ':condition'  => (string) $where,
130
                ':projection' => $this->createProjection()->formatFieldsWithFieldAlias(),
131
            ]
132
        );
133
134
        $iterator = $this->query($sql, array_merge(array_values($updates), $where->getValues()));
135
136
        if ($iterator->isEmpty()) {
137
            return null;
138
        }
139
140
        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...
141
    }
142
143
    /**
144
     * deleteOne
145
     *
146
     * Delete an entity from a table. Entity is passed by reference and is
147
     * updated with the values fetched from the deleted record.
148
     *
149
     * @access public
150
     * @param  FlexibleEntityInterface  $entity
151
     * @return Model                    $this
152
     */
153
    public function deleteOne(FlexibleEntityInterface &$entity)
154
    {
155
        $entity = $this->deleteByPK($entity->fields($this->getStructure()->getPrimaryKey()));
156
157
        return $this;
158
    }
159
160
    /**
161
     * deleteByPK
162
     *
163
     * Delete a record from its primary key. The deleted entity is returned or
164
     * null if not found.
165
     *
166
     * @access public
167
     * @param  array          $primary_key
168
     * @throws ModelException
169
     * @return FlexibleEntityInterface
170
     */
171
    public function deleteByPK(array $primary_key)
172
    {
173
        $where = $this
174
            ->checkPrimaryKey($primary_key)
175
            ->getWhereFrom($primary_key)
176
        ;
177
178
        return $this->deleteWhere($where)->current();
179
    }
180
181
    /**
182
     * deleteWhere
183
     *
184
     * Delete records by a given condition. A collection of all deleted entries is returned.
185
     *
186
     * @param        $where
187
     * @param  array $values
188
     * @return CollectionIterator
189
     */
190
    public function deleteWhere($where, array $values = [])
191
    {
192
        if (!$where instanceof Where) {
193
            $where = new Where($where, $values);
194
        }
195
196
        $sql = strtr(
197
            "delete from :relation where :condition returning :projection",
198
            [
199
                ':relation'   => $this->getStructure()->getRelation(),
200
                ':condition'  => (string) $where,
201
                ':projection' => $this->createProjection()->formatFieldsWithFieldAlias(),
202
            ]
203
        );
204
205
        $collection = $this->query($sql, $where->getValues());
206
        foreach ($collection as $entity) {
207
            $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...
208
        }
209
        $collection->rewind();
210
211
        return $collection;
212
    }
213
214
    /**
215
     * createAndSave
216
     *
217
     * Create a new entity from given values and save it in the database.
218
     *
219
     * @access public
220
     * @param  array          $values
221
     * @return FlexibleEntityInterface
222
     */
223
    public function createAndSave(array $values)
224
    {
225
        $entity = $this->createEntity($values);
226
        $this->insertOne($entity);
227
228
        return $entity;
229
    }
230
231
    /**
232
     * getEscapedFieldList
233
     *
234
     * Return a comma separated list with the given escaped field names.
235
     *
236
     * @access protected
237
     * @param  array  $fields
238
     * @return string
239
     */
240
    public function getEscapedFieldList(array $fields)
241
    {
242
        return join(
243
            ', ',
244
            array_map(
245
                function ($field) { return $this->escapeIdentifier($field); },
246
                $fields
247
            ));
248
    }
249
250
    /**
251
     * getParametersList
252
     *
253
     * Create a parameters list from values.
254
     *
255
     * @access protected
256
     * @param  array    $values
257
     * @return array    $escape codes
258
     */
259
    protected function getParametersList(array $values)
260
    {
261
        $parameters = [];
262
263
        foreach ($values as $name => $value) {
264
            $parameters[$name] = sprintf(
265
                "$*::%s",
266
                $this->getStructure()->getTypeFor($name)
267
            );
268
        }
269
270
        return $parameters;
271
    }
272
}
273