HydrationPlan   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 15
c 0
b 0
f 0
lcom 1
cbo 2
dl 0
loc 199
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A loadConverters() 0 22 3
A getFieldType() 0 4 1
A isArray() 0 4 1
A hydrate() 0 6 1
A dry() 0 4 1
A freeze() 0 4 1
A convert() 0 17 3
A createEntity() 0 8 1
A getConverterForField() 0 14 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\Foundation\Session\Session;
13
use PommProject\Foundation\Converter\ConverterClient;
14
use PommProject\ModelManager\Model\FlexibleEntity\FlexibleEntityInterface;
15
16
/**
17
 * HydrationPlan
18
 *
19
 * Tell the FlexibleEntityConverter how to hydrate fields.
20
 *
21
 * @package     ModelManager
22
 * @copyright   2014 - 2015 Grégoire HUBERT
23
 * @author      Grégoire HUBERT
24
 * @license     X11 {@link http://opensource.org/licenses/mit-license.php}
25
 */
26
class HydrationPlan
27
{
28
    protected $session;
29
    protected $projection;
30
    protected $converters = [];
31
    protected $field_types = [];
32
33
34
    /**
35
     * Construct
36
     *
37
     * @access  public
38
     * @param   Projection $projection
39
     * @param   Session    $session
40
     */
41
    public function __construct(Projection $projection, Session $session)
42
    {
43
        $this->projection = $projection;
44
        $this->session    = $session;
45
46
        $this->loadConverters();
47
    }
48
49
    /**
50
     * loadConverters
51
     *
52
     * Cache converters needed for this result set.
53
     *
54
     * @access protected
55
     * @return HydrationPlan    $this
56
     */
57
    protected function loadConverters()
58
    {
59
        foreach ($this->projection as $name => $type) {
60
            if ($this->projection->isArray($name)) {
61
                $this->converters[$name] = $this
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface PommProject\Foundation\Client\ClientInterface as the method getConverter() does only exist in the following implementations of said interface: PommProject\Foundation\Converter\ConverterClient.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
62
                    ->session
63
                    ->getClientUsingPooler('converter', 'array')
64
                    ->getConverter()
65
                    ;
66
            } else {
67
                $this->converters[$name] = $this
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface PommProject\Foundation\Client\ClientInterface as the method getConverter() does only exist in the following implementations of said interface: PommProject\Foundation\Converter\ConverterClient.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
68
                    ->session
69
                    ->getClientUsingPooler('converter', $type)
70
                    ->getConverter()
71
                    ;
72
            }
73
74
            $this->field_types[$name] = $type;
75
        }
76
77
        return $this;
78
    }
79
80
81
    /**
82
     * getFieldType
83
     *
84
     * Return the type of the given field. Proxy to Projection::getFieldType().
85
     *
86
     * @access public
87
     * @param  string $name
88
     * @return string
89
     */
90
    public function getFieldType($name)
91
    {
92
        return $this->projection->getFieldType($name);
93
    }
94
95
    /**
96
     * isArray
97
     *
98
     * Tell if the given field is an array or not.
99
     *
100
     * @access public
101
     * @param  string $name
102
     * @return bool
103
     */
104
    public function isArray($name)
105
    {
106
        return $this->projection->isArray($name);
107
    }
108
109
110
    /**
111
     * hydrate
112
     *
113
     * Take values fetched from the database, launch conversion system and
114
     * hydrate the FlexibleEntityInterface through the mapper.
115
     *
116
     * @access public
117
     * @param  array $values
118
     * @return FlexibleEntityInterface
119
     */
120
    public function hydrate(array $values)
121
    {
122
        $values = $this->convert('fromPg', $values);
123
124
        return $this->createEntity($values);
125
    }
126
127
    /**
128
     * dry
129
     *
130
     * Return values converted to Pg.
131
     *
132
     * @access public
133
     * @param  array    $values
134
     * @return array
135
     */
136
    public function dry(array $values)
137
    {
138
        return $this->convert('toPg', $values);
139
    }
140
141
    /**
142
     * freeze
143
     *
144
     * Return values converted to Pg standard output.
145
     *
146
     * @access public
147
     * @param  array $values
148
     * @return array converted values
149
     */
150
    public function freeze(array $values)
151
    {
152
        return $this->convert('toPgStandardFormat', $values);
153
    }
154
155
    /**
156
     * convert
157
     *
158
     * Convert values from / to postgres.
159
     *
160
     * @access protected
161
     * @param  string   $from_to
162
     * @param  array    $values
163
     * @return array
164
     */
165
    protected function convert($from_to, array $values)
166
    {
167
        $out_values = [];
168
169
        foreach ($values as $name => $value) {
170
            if (isset($this->converters[$name])) {
171
                $out_values[$name] = $this
172
                    ->converters[$name]
173
                    ->$from_to($value, $this->field_types[$name], $this->session)
174
                    ;
175
            } else {
176
                $out_values[$name] = $value;
177
            }
178
        }
179
180
        return $out_values;
181
    }
182
183
    /**
184
     * createEntity
185
     *
186
     * Instantiate FlexibleEntityInterface from converted values.
187
     *
188
     * @access protected
189
     * @param  array $values
190
     * @return FlexibleEntityInterface
191
     */
192
    protected function createEntity(array $values)
193
    {
194
        $class = $this->projection->getFlexibleEntityClass();
195
196
        return (new $class())
197
            ->hydrate($values)
198
            ;
199
    }
200
201
    /**
202
     * getConverterForField
203
     *
204
     * Return the converter client associated with a field.
205
     *
206
     * @access public
207
     * @param  string $field_name
208
     * @return ConverterClient
209
     */
210
    public function getConverterForField($field_name)
211
    {
212
        if (!isset($this->converters[$field_name])) {
213
            throw new \RuntimeException(
214
                sprintf(
215
                    "Error, '%s' field has no converters registered. Fields are {%s}.",
216
                    $field_name,
217
                    join(', ', array_keys($this->converters))
218
                )
219
            );
220
        }
221
222
        return $this->converters[$field_name];
223
    }
224
}
225