Completed
Push — master ( 2723b8...b8ac50 )
by Jelle
03:22
created

EntityManager::reverseMapProperties()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 12
Code Lines 8

Duplication

Lines 3
Ratio 25 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 3
loc 12
rs 9.2
cc 4
eloc 8
nc 5
nop 2
1
<?php
2
/**
3
 * @file
4
 * Contains \TheSportsDb\Entity\EntityManager.
5
 */
6
7
namespace TheSportsDb\Entity;
8
9
use TheSportsDb\Entity\Factory\FactoryContainerInterface;
10
use TheSportsDb\Entity\Repository\RepositoryContainerInterface;
11
use FastNorth\PropertyMapper\MapperInterface;
12
use FastNorth\PropertyMapper\Map;
13
use TheSportsDb\PropertyMapper\Transformer\Callback;
14
15
/**
16
 * Default implementation for entity managers.
17
 *
18
 * @author Jelle Sebreghts
19
 */
20
class EntityManager implements EntityManagerInterface {
21
  
22
  /**
23
   * The factory container.
24
   * 
25
   * @var TheSportsDb\Entity\Factory\FactoryContainerInterface
26
   */
27
  protected $factoryContainer;
28
  
29
  /**
30
   * The repository container.
31
   * 
32
   * @var TheSportsDb\Entity\Repository\RepositoryContainerInterface
33
   */
34
  protected $repositoryContainer;
35
36
  /**
37
   * Map entity types to classes.
38
   *
39
   * @var array
40
   */
41
  protected $classes = array();
42
43
  /**
44
   * Property map definitions.
45
   *
46
   * @var array
47
   */
48
  protected $propertyMapDefinitions = array();
49
50
  /**
51
   * Property map definitions.
52
   *
53
   * @var array
54
   */
55
  protected $propertyMaps = array();
56
57
  protected $propertyMapper;
58
59
60
  const EMPTYPROPERTYPLACEHOLDER = '__EMPTY_PROPERTY_PLACEHOLDER__';
61
62
63
  public function __construct(MapperInterface $propertyMapper, FactoryContainerInterface $factoryContainer = NULL, RepositoryContainerInterface $repositoryContainer = NULL) {
64
    if ($factoryContainer instanceof FactoryContainerInterface) {
65
      $this->factoryContainer = $factoryContainer;
0 ignored issues
show
Documentation Bug introduced by
It seems like $factoryContainer of type object<TheSportsDb\Entit...toryContainerInterface> is incompatible with the declared type object<TheSportsDb\Entit...toryContainerInterface> of property $factoryContainer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
66
    }
67
    if ($repositoryContainer instanceof RepositoryContainerInterface) {
68
      $this->repositoryContainer = $repositoryContainer;
0 ignored issues
show
Documentation Bug introduced by
It seems like $repositoryContainer of type object<TheSportsDb\Entit...toryContainerInterface> is incompatible with the declared type object<TheSportsDb\Entit...toryContainerInterface> of property $repositoryContainer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
69
    }
70
    $this->propertyMapper = $propertyMapper;
71
  }
72
73
  public function setFactoryContainer(FactoryContainerInterface $factoryContainer) {
74
    if ($this->factoryContainer instanceof FactoryContainerInterface) {
75
      throw new \Exception('Factory container already set.');
76
    }
77
    $this->factoryContainer = $factoryContainer;
0 ignored issues
show
Documentation Bug introduced by
It seems like $factoryContainer of type object<TheSportsDb\Entit...toryContainerInterface> is incompatible with the declared type object<TheSportsDb\Entit...toryContainerInterface> of property $factoryContainer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78
  }
79
80
  public function setRepositoryContainer(RepositoryContainerInterface $repositoryContainer) {
81
    if ($this->repositoryContainer instanceof RepositoryContainerInterface) {
82
      throw new \Exception('Repository container already set.');
83
    }
84
    $this->repositoryContainer = $repositoryContainer;
0 ignored issues
show
Documentation Bug introduced by
It seems like $repositoryContainer of type object<TheSportsDb\Entit...toryContainerInterface> is incompatible with the declared type object<TheSportsDb\Entit...toryContainerInterface> of property $repositoryContainer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
85
  }
86
87
88
  /**
89
   * {@inheritdoc}
90
   */
91
  public function repository($entityType) {
92
    if ($this->repositoryContainer instanceof RepositoryContainerInterface) {
93
      return $this->repositoryContainer->getRepository($entityType);
94
    }
95
    throw new \Exception('No repository container set.');
96
  }
97
98
  /**
99
   * {@inheritdoc}
100
   */
101
  public function factory($entityType) {
102
    if ($this->factoryContainer instanceof FactoryContainerInterface) {
103
      return $this->factoryContainer->getFactory($entityType);
104
    }
105
    throw new \Exception('No factory container set.');
106
  }
107
108
  /**
109
   * {@inheritdoc}
110
   */
111
  public function registerClass($entityType, $realClass = NULL, $proxyClass = NULL) {
112 View Code Duplication
    if (is_null($realClass)) {
1 ignored issue
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
      $realClass = (new \ReflectionClass(static::class))->getNamespaceName() . '\\' . ucfirst($entityType);
114
    }
115 View Code Duplication
    if (is_null($proxyClass)) {
1 ignored issue
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...
116
      $proxyClass = (new \ReflectionClass($realClass))->getNamespaceName() . '\\Proxy\\' . ucfirst($entityType) . 'Proxy';
117
    }
118
    if (!class_exists($realClass)) {
119
      throw new \Exception('Class ' . $realClass . 'not found.');
120
    }
121
    if (!class_exists($proxyClass)) {
122
      throw new \Exception('Class ' . $proxyClass . 'not found.');
123
    }
124
    $this->classes[$entityType] = array(
125
      'real' => $realClass,
126
      'proxy' => $proxyClass
127
    );
128
    return $this->classes[$entityType];
129
  }
130
131
  /**
132
   * {@inheritdoc}
133
   */
134
  public function getPropertyMapDefinition($entityType) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
135
    if (!isset($this->propertyMapDefinitions[$entityType])) {
136
      $propertyMapDefinition = new \ReflectionMethod($this->getClass($entityType), 'getPropertyMapDefinition');
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 21 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
137
      $this->propertyMapDefinitions[$entityType] = $propertyMapDefinition->invoke(NULL);
138
    }
139
    return $this->propertyMapDefinitions[$entityType];
140
  }
141
142
  /**
143
   * {@inheritdoc}
144
   */
145
  public function getClass($entityType, $type = 'real') {
146
    if (!isset($this->classes[$entityType][$type])) {
147
      throw new \Exception(ucfirst($type) . ' class for ' . $entityType . ' not registered.');
148
    }
149
    return $this->classes[$entityType][$type];
150
  }
151
152
  /**
153
   * {@inheritdoc}
154
   */
155
  public function mapProperties(\stdClass $values, $entityType) {
156
    $mapped = new \stdClass();
157
    foreach ($this->getPropertyMapDefinition($entityType) as $propertyDefinition) {
158
      $mapped->{$propertyDefinition[1]} = NULL;
159 View Code Duplication
      if (!isset($values->{$propertyDefinition[0]})) {
1 ignored issue
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...
160
        $values->{$propertyDefinition[0]} = static::EMPTYPROPERTYPLACEHOLDER;
161
      }
162
    }
163
    return $this->sanitizeObject($this->propertyMapper->process($values, $mapped, $this->getPropertyMap($entityType)));
1 ignored issue
show
Documentation introduced by
$this->propertyMapper->p...opertyMap($entityType)) is of type array|object, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
164
  }
165
166
167
  /**
168
   * {@inheritdoc}
169
   */
170
  public function reverseMapProperties(\stdClass $values, $entityType) {
171
    $reversed = new \stdClass();
172
    foreach ($this->getPropertyMapDefinition($entityType) as $propertyDefinition) {
173
      if (!isset($reversed->{$propertyDefinition[0]})) {
174
        $reversed->{$propertyDefinition[0]} = static::EMPTYPROPERTYPLACEHOLDER;
175
      }
176 View Code Duplication
      if (!isset($values->{$propertyDefinition[1]})) {
1 ignored issue
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...
177
        $values->{$propertyDefinition[1]} = static::EMPTYPROPERTYPLACEHOLDER;
178
      }
179
    }
180
    return $this->sanitizeObject($this->propertyMapper->reverse($reversed, $values, $this->getPropertyMap($entityType)));
1 ignored issue
show
Documentation introduced by
$this->propertyMapper->r...opertyMap($entityType)) is of type array|object, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
181
  }
182
183
  /**
184
   * Initializes the property map.
185
   */
186
  protected function initPropertyMap($entityType) {
187
    $this->propertyMaps[$entityType] = new Map();
188
    $entityManager = $this;
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 19 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
189
    foreach ($this->getPropertyMapDefinition($entityType) as $args) {
190
      if (isset($args[2]) && is_array($args[2])) {
191
        $transform = $args[2][0];
192
        $reverse = $args[2][1];
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
193
        $args[2] = new Callback(
1 ignored issue
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
194 View Code Duplication
          function ($value, $context) use ($entityManager, $transform) {
1 ignored issue
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...
195
            if ($entityManager->isEmptyValue($value)) {
196
              return $value;
197
            }
198
            return call_user_func_array($transform, array($value, $context, $entityManager));
199
          },
200 View Code Duplication
          function ($value, $context) use ($entityManager, $reverse) {
1 ignored issue
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...
201
            if ($entityManager->isEmptyValue($value)) {
202
              return $value;
203
            }
204
            return call_user_func_array($reverse, array($value, $context, $entityManager));
205
          }
206
        );
207
      }
208
      call_user_func_array(array($this->propertyMaps[$entityType], 'map'), $args);
209
    }
210
  }
211
212
  /**
213
   * Gets the property map.
214
   *
215
   * @return FastNorth\PropertyMapper\Map
216
   *   The property map.
217
   */
218
  protected function getPropertyMap($entityType) {
219
    if (!isset($this->propertyMaps[$entityType])) {
220
      $this->initPropertyMap($entityType);
221
    }
222
    return $this->propertyMaps[$entityType];
223
  }
224
225
  protected function sanitizeObject(\stdClass $object) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
226
    $arr = (array) $object;
227
    foreach ($arr as $prop => $val) {
228
      if ($this->isEmptyValue($val)) {
229
        unset($arr[$prop]);
230
      }
231
    }
232
    return (object) $arr;
233
  }
234
235
236
  public function isEmptyValue($value) {
237
    return $value === static::EMPTYPROPERTYPLACEHOLDER;
238
  }
239
}
240