PgEntity   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 218
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 5
dl 0
loc 218
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 2
A fromPg() 0 24 3
A transformData() 0 16 3
A cacheEntity() 0 7 1
A toPg() 0 15 2
A createHydrationPlan() 0 7 1
A getFields() 0 11 2
A checkData() 0 14 2
A toPgStandardFormat() 0 24 5
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\Converter;
11
12
use PommProject\Foundation\Converter\ConverterInterface;
13
use PommProject\Foundation\Exception\ConverterException;
14
use PommProject\Foundation\Session\Session;
15
use PommProject\ModelManager\Model\FlexibleEntity\FlexibleEntityInterface;
16
use PommProject\ModelManager\Model\HydrationPlan;
17
use PommProject\ModelManager\Model\IdentityMapper;
18
use PommProject\ModelManager\Model\Projection;
19
use PommProject\ModelManager\Model\RowStructure;
20
21
/**
22
 * PgEntity
23
 *
24
 * Entity converter.
25
 * It handles row types and composite types.
26
 *
27
 * @package   ModelManager
28
 * @copyright 2014 - 2015 Grégoire HUBERT
29
 * @author    Grégoire HUBERT
30
 * @license   X11 {@link http://opensource.org/licenses/mit-license.php}
31
 * @see       ConverterInterface
32
 */
33
class PgEntity implements ConverterInterface
34
{
35
    protected $row_structure;
36
    protected $identity_mapper;
37
    protected $flexible_entity_class;
38
39
40
    /**
41
     * Constructor.
42
     *
43
     * @access public
44
     * @param                $flexible_entity_class
45
     * @param RowStructure   $structure
46
     * @param IdentityMapper $identity_mapper
47
     */
48
    public function __construct(
49
        $flexible_entity_class,
50
        RowStructure $structure,
51
        IdentityMapper $identity_mapper = null
52
    ) {
53
        $this->flexible_entity_class    = $flexible_entity_class;
54
        $this->row_structure            = $structure;
55
        $this->identity_mapper          = $identity_mapper === null
56
            ? new IdentityMapper()
57
            : $identity_mapper
58
            ;
59
    }
60
61
    /**
62
     * fromPg
63
     *
64
     * Embeddable entities are converted here.
65
     *
66
     * @see ConverterInterface
67
     */
68
    public function fromPg($data, $type, Session $session)
69
    {
70
        if (empty($data)) {
71
            return null;
72
        }
73
74
        $data = trim($data, '()');
75
76
        if ($type instanceof Projection) {
77
            $projection = $type;
78
        } else {
79
            $projection = new Projection(
80
                $this->flexible_entity_class,
81
                $this->row_structure->getDefinition()
82
            );
83
        }
84
85
        $entity = (new HydrationPlan(
86
            $projection,
87
            $session
88
        ))->hydrate($this->transformData($data, $projection));
89
90
        return $this->cacheEntity($entity);
91
    }
92
93
    /**
94
     * transformData
95
     *
96
     * Split data into an array prefixed with field names.
97
     *
98
     * @access private
99
     * @param  string       $data
100
     * @param  Projection   $projection
101
     * @return array
102
     */
103
    private function transformData($data, Projection $projection)
104
    {
105
        $values         = str_getcsv($data);
106
        $definition     = $projection->getFieldNames();
107
        $out_values     = [];
108
        $values_count   = count($values);
109
110
        for ($index = 0; $index < $values_count; $index++) {
111
            $out_values[$definition[$index]] = preg_match(':^{.*}$:', $values[$index])
112
                ? stripcslashes($values[$index])
113
                : $values[$index]
114
                ;
115
        }
116
117
        return $out_values;
118
    }
119
120
    /**
121
     * cacheEntity
122
     *
123
     * Check entity against the cache.
124
     *
125
     * @access public
126
     * @param  FlexibleEntityInterface   $entity
127
     * @return FlexibleEntityInterface
128
     */
129
    public function cacheEntity(FlexibleEntityInterface $entity)
130
    {
131
        return $this
132
            ->identity_mapper
133
            ->fetch($entity, $this->row_structure->getPrimaryKey())
134
            ;
135
    }
136
137
    /**
138
     * toPg
139
     *
140
     * @see ConverterInterface
141
     */
142
    public function toPg($data, $type, Session $session)
143
    {
144
        if ($data === null) {
145
            return sprintf("NULL::%s", $type);
146
        }
147
148
        $fields = $this->getFields($data);
149
        $hydration_plan = $this->createHydrationPlan($session);
150
151
        return sprintf(
152
            "row(%s)::%s",
153
            join(',', $hydration_plan->dry($fields)),
154
            $type
155
        );
156
    }
157
158
    /**
159
     * createHydrationPlan
160
     *
161
     * Create a new hydration plan.
162
     *
163
     * @access protected
164
     * @param  Session          $session
165
     * @return HydrationPlan
166
     */
167
    protected function createHydrationPlan(Session $session)
168
    {
169
        return new HydrationPlan(
170
            new Projection($this->flexible_entity_class, $this->row_structure->getDefinition()),
171
            $session
172
        );
173
    }
174
175
    /**
176
     * getFields
177
     *
178
     * Return the fields array.
179
     *
180
     * @access protected
181
     * @param mixed $data
182
     * @return array
183
     */
184
    protected function getFields($data)
185
    {
186
        if (is_array($data)) {
187
            $fields = $data;
188
        } else {
189
            $this->checkData($data);
190
            $fields = $data->fields();
191
        }
192
193
        return $fields;
194
    }
195
196
    /**
197
     * checkData
198
     *
199
     * Check if the given data is the right entity.
200
     *
201
     * @access protected
202
     * @param  mixed        $data
203
     * @throws  ConverterException
204
     * @return PgEntity     $this
205
     */
206
    protected function checkData($data)
207
    {
208
        if (!$data instanceof $this->flexible_entity_class) {
209
            throw new ConverterException(
210
                sprintf(
211
                    "This converter only knows how to convert entities of type '%s' ('%s' given).",
212
                    $this->flexible_entity_class,
213
                    get_class($data)
214
                )
215
            );
216
        }
217
218
        return $this;
219
    }
220
221
    /**
222
     * toPgStandardFormat
223
     *
224
     * @see ConverterInterface
225
     */
226
    public function toPgStandardFormat($data, $type, Session $session)
227
    {
228
        if ($data === null) {
229
            return null;
230
        }
231
232
        $fields = $this->getFields($data);
233
234
        return
235
            sprintf("(%s)",
236
                join(',', array_map(function ($val) {
237
                    if ($val === null) {
238
                        return '';
239
                    } elseif ($val === '') {
240
                        return '""';
241
                    } elseif (preg_match('/[,\s]/', $val)) {
242
                        return sprintf('"%s"', str_replace('"', '""', $val));
243
                    } else {
244
                        return $val;
245
                    }
246
                }, $this->createHydrationPlan($session)->freeze($fields)
247
                ))
248
            );
249
    }
250
}
251