Completed
Push — develop ( f5bc45...3ea57c )
by
unknown
49:10 queued 12:24
created

SnapshotRepository::getCopyAttributes()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 2
1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @license MIT
7
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
8
 */
9
  
10
/** */
11
namespace Core\Repository;
12
13
use Core\Entity\Collection\ArrayCollection;
14
use Core\Entity\EntityInterface;
15
use Core\Entity\Hydrator\EntityHydrator;
16
use Core\Entity\IdentifiableEntityInterface;
17
use Core\Entity\SnapshotAttributesProviderInterface;
18
use Core\Entity\SnapshotInterface;
19
use Doctrine\Common\Collections\Collection;
20
use Doctrine\ODM\MongoDB\DocumentRepository;
21
use Zend\Hydrator\HydratorInterface;
22
23
/**
24
 * ${CARET}
25
 * 
26
 * @author Mathias Gelhausen <[email protected]>
27
 * @todo write test 
28
 */
29
class SnapshotRepository extends DocumentRepository
30
{
31
    /**
32
     *
33
     *
34
     * @var HydratorInterface
35
     */
36
    protected $hydrator;
37
38
    /**
39
     *
40
     *
41
     * @var HydratorInterface
42
     */
43
    protected $sourceHydrator;
44
45
    /**
46
     *
47
     *
48
     * @var array
49
     */
50
    protected $snapshotAttributes = [];
51
52
    /**
53
     * @param \Zend\Hydrator\HydratorInterface $hydrator
54
     *
55
     * @return self
56
     */
57
    public function setHydrator($hydrator)
58
    {
59
        $this->hydrator = $hydrator;
60
61
        return $this;
62
    }
63
64
    /**
65
     * @return \Zend\Hydrator\HydratorInterface
66
     */
67
    public function getHydrator()
68
    {
69
        if (!$this->hydrator) {
70
            $this->setHydrator(new EntityHydrator());
71
        }
72
        return $this->hydrator;
73
    }
74
75
    /**
76
     * @param \Zend\Hydrator\HydratorInterface $sourceHydrator
77
     *
78
     * @return self
79
     */
80
    public function setSourceHydrator($sourceHydrator)
81
    {
82
        $this->sourceHydrator = $sourceHydrator;
83
84
        return $this;
85
    }
86
87
    /**
88
     * @return \Zend\Hydrator\HydratorInterface
89
     */
90
    public function getSourceHydrator()
91
    {
92
        if (!$this->sourceHydrator) {
93
            return $this->getHydrator();
94
        }
95
96
        return $this->sourceHydrator;
97
    }
98
99
    /**
100
     * @param array $snapshotAttributes
101
     *
102
     * @return self
103
     */
104
    public function setSnapshotAttributes($snapshotAttributes)
105
    {
106
        $this->snapshotAttributes = $snapshotAttributes;
107
108
        return $this;
109
    }
110
111
    /**
112
     * @return array
113
     */
114
    public function getSnapshotAttributes()
115
    {
116
        return $this->snapshotAttributes;
117
    }
118
119
    public function create(EntityInterface $source, $persist = true)
120
    {
121
122
        $snapshot = $this->getDocumentName();
123
        $snapshot = new $snapshot($source);
124
125
        $this->copy($source, $snapshot);
126
127
        if ($persist) {
128
            $this->store($snapshot);
129
        }
130
131
        return $snapshot;
132
    }
133
134
    protected function copy($source, $target, $inverse = false)
135
    {
136
        if ($inverse) {
137
            $attributes = $this->getCopyAttributes($target, $source);
138
            $sourceHydrator = $this->getHydrator();
139
            $targetHydrator = $this->getSourceHydrator();
140
        } else {
141
            $attributes = $this->getCopyAttributes($source, $target);
142
            $sourceHydrator = $this->getSourceHydrator();
143
            $targetHydrator = $this->getHydrator();
144
            $source = clone $source;
145
        }
146
147
148
        $data = $sourceHydrator->extract($source);
149
        $data = array_intersect_key($data, array_flip($attributes));
150
        $targetHydrator->hydrate($data, $target);
151
    }
152
153
    protected function getCopyAttributes($source, $target)
154
    {
155
        if ($source instanceOf SnapshotAttributesProviderInterface) {
156
            return $source->getSnapshotAttributes();
157
        }
158
159
        if ($target instanceOf SnapshotAttributesProviderInterface) {
160
            return $target->getSnapshotAttributes();
161
        }
162
163
        return $this->getSnapshotAttributes();
164
    }
165
166
    public function merge(SnapshotInterface $snapshot, $snapshotDraftStatus = false)
167
    {
168
        $this->checkEntityType($snapshot);
169
170
        $meta       = $snapshot->getSnapshotMeta();
171
        $entity     = $snapshot->getOriginalEntity();
172
173
        $meta->setIsDraft((bool) $snapshotDraftStatus);
0 ignored issues
show
Bug introduced by
The method setIsDraft does only exist in Core\Entity\SnapshotMeta, but not in Core\Entity\SnapshotInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
174
175
        $this->copy($snapshot, $entity, true);
176
177
        return $entity;
178
    }
179
180
    public function diff(SnapshotInterface $snapshot)
181
    {
182
        $entity = $snapshot->getEntity();
0 ignored issues
show
Bug introduced by
The method getEntity() does not seem to exist on object<Core\Entity\SnapshotInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
183
        $attributes = $this->getCopyAttributes($entity, $snapshot);
0 ignored issues
show
Unused Code introduced by
$attributes 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...
184
185
186
    }
187
188
    public function findLatest($sourceId, $isDraft = false)
189
    {
190
        return $this->createQueryBuilder()
191
          ->field('snapshotEntity')->equals(new \MongoId($sourceId))
192
          ->field('snapshotMeta.isDraft')->equals($isDraft)
193
          ->sort('snapshotMeta.dateCreated.date', 'desc')
194
          ->limit(1)
195
          ->getQuery()
196
          ->getSingleResult();
197
198
    }
199
200
    public function findBySourceId($sourceId, $includeDrafts = false)
201
    {
202
        $criteria = ['snapshotEntity' => $sourceId];
203
204
        if (!$includeDrafts) {
205
            $criteria['snapshotMeta.isDraft'] = false;
206
        }
207
208
        return $this->findBy($criteria);
209
    }
210
211
    /**
212
     * @param $entity
213
     * @throws \InvalidArgumentException
214
     * @return self
215
     */
216
    public function store($entity)
217
    {
218
        $this->checkEntityType($entity);
219
        $this->dm->persist($entity);
220
        $this->dm->flush($entity);
221
222
        return $this;
223
    }
224
225
    public function remove($entity)
226
    {
227
        $this->checkEntityType($entity);
228
        $this->dm->remove($entity);
229
230
        return $this;
231
    }
232
233
    public function removeAll($sourceId)
234
    {
235
236
    }
237
238
    protected function checkEntityType($entity)
239
    {
240
        if ( !is_a($entity,  $this->getDocumentName()) ) {
241
            throw new \InvalidArgumentException(sprintf(
242
                'Entity must be of type %s but recieved %s instead',
243
                $this->getDocumentName(),
244
                get_class($entity)
245
            ));
246
        }
247
248
    }
249
250
    protected function extract($source, array $attributes = [])
251
    {
252
        $hydrator = $this->getSourceHydrator();
253
        $data     = $hydrator->extract($source);
254
        $hydrate  = [];
255
256
        if (empty($attributes)) {
257
            $attributes = array_keys($data);
258
        }
259
260
        foreach ($attributes as $key => $spec) {
261
            if (is_numeric($key)) {
262
                $key = $spec;
263
                $spec = null;
264
            }
265
266
            if ($data[$key] instanceOf EntityInterface) {
267
                $hydrate[$key] = clone $data[$key];
268
269
            } else if ($data[$key] instanceOf Collection) {
270
                $collection = new ArrayCollection();
271
                foreach ($data[$key] as $item) {
272
                    $collection->add(clone $item);
273
                }
274
                $hydrate[$key] = $collection;
275
276
            } else {
277
                $hydrate[$key] = $data[$key];
278
            }
279
        }
280
281
        return $hydrate;
282
    }
283
}
284