Completed
Push — master ( 086a41...409693 )
by Thomas
25s queued 11s
created

ResultRepository   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 18
eloc 39
c 2
b 0
f 1
dl 0
loc 146
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A retrieve() 0 5 3
A __construct() 0 3 1
A addEntity() 0 9 2
A completePrimaryKeys() 0 12 4
A getResults() 0 20 5
A buildChecksum() 0 3 1
A addResult() 0 13 2
1
<?php
2
3
namespace ORM\Testing\EntityFetcherMock;
4
5
use Mockery as m;
6
use ORM\Entity;
7
use ORM\EntityFetcher;
8
use ORM\EntityManager;
9
10
class ResultRepository
11
{
12
    const RANDOM_KEY_MIN = 1000000000;
13
    const RANDOM_KEY_MAX = 1000999999;
14
15
    /** @var Entity[][] */
16
    protected $primaryKeyMap = [];
17
18
    /** @var Result[][] */
19
    protected $results = [];
20
21
    /** @var EntityManager */
22
    protected $em;
23
24
    /**
25
     * ResultRepository constructor.
26
     *
27
     * @param EntityManager $em
28
     */
29
    public function __construct(EntityManager $em)
30
    {
31
        $this->em = $em;
32
    }
33
34
    /**
35
     * Fill the primary keys of $entities
36
     *
37
     * If the primary key is incomplete the missing attributes will be filled with a random integer between
38
     * RANDOM_KEY_MIN and RANDOM_KEY_MAX (at the time writing this it is 1000000000 and 1000999999).
39
     *
40
     * @param Entity ...$entities
41
     * @return Entity[]
42
     */
43
    public static function completePrimaryKeys(Entity ...$entities)
44
    {
45
        // complete the primary keys with random numbers
46
        foreach ($entities as $entity) {
47
            foreach ($entity::getPrimaryKeyVars() as $attribute) {
48
                if ($entity->$attribute === null) {
49
                    $entity->$attribute = mt_rand(static::RANDOM_KEY_MIN, static::RANDOM_KEY_MAX);
50
                }
51
            }
52
        }
53
54
        return $entities;
55
    }
56
57
    /**
58
     * Add an entity to be fetched by primary key
59
     *
60
     * The entity needs to have a primary key if not it will be filled with random values between RANDOM_KEY_MIN and
61
     * RANDOM_KEY_MAX (at the time writing this it is 1000000000 and 1000999999).
62
     *
63
     * You can pass mocks from Entity too but we need to call `Entity::getPrimaryKey()`.
64
     *
65
     * @param Entity $entity
66
     */
67
    public function addEntity(Entity $entity)
68
    {
69
        static::completePrimaryKeys($entity);
70
        $class = get_class($entity);
71
        if ($entity instanceof m\MockInterface) {
72
            $class = (new \ReflectionClass($entity))->getParentClass()->getName();
73
        }
74
75
        $this->primaryKeyMap[$class][static::buildChecksum($entity->getPrimaryKey())] = $entity;
76
    }
77
78
    /**
79
     * Retrieve an entity by $primaryKey
80
     *
81
     * @param string $class
82
     * @param array $primaryKey
83
     * @return Entity|null
84
     */
85
    public function retrieve($class, array $primaryKey)
86
    {
87
        $checksum = static::buildChecksum($primaryKey);
88
        return isset($this->primaryKeyMap[$class]) && isset($this->primaryKeyMap[$class][$checksum]) ?
89
            $this->primaryKeyMap[$class][$checksum] : null;
90
    }
91
92
    /**
93
     * Create and add a EntityFetcherMock\Result for $class
94
     *
95
     * As the results are mocked to come from the database they will also get a primary key if they don't have already.
96
     *
97
     * @param $class
98
     * @param Entity ...$entities
99
     * @return Result|m\MockInterface
100
     */
101
    public function addResult($class, Entity ...$entities)
102
    {
103
        /** @var Result|m\MockInterface $result */
104
        $result = m::mock(Result::class, [$this->em, $class])->makePartial();
105
        $result->addEntities(...static::completePrimaryKeys(...$entities));
106
107
        if (!isset($this->results[$class])) {
108
            $this->results[$class] = [spl_object_hash($result) => $result];
109
        } else {
110
            $this->results[$class][spl_object_hash($result)] = $result;
111
        }
112
113
        return $result;
114
    }
115
116
    /**
117
     * Get the results for $class and $query
118
     *
119
     * The EntityFetcherMock\Result gets a quality for matching this query. Only the highest quality will be used.
120
     *
121
     * @param string $class
122
     * @param EntityFetcher $fetcher
123
     * @return array
124
     */
125
    public function getResults($class, EntityFetcher $fetcher)
126
    {
127
        if (!isset($this->results[$class])) {
128
            return [];
129
        }
130
131
        $results = [];
132
        foreach ($this->results[$class] as $objHash => $result) {
133
            if ($quality = $result->compare($fetcher)) {
134
                $results[$objHash] = $quality;
135
            }
136
        }
137
138
        if (empty($results)) {
139
            return [];
140
        }
141
142
        arsort($results, SORT_DESC);
143
        $objHash = array_keys($results)[0];
144
        return $this->results[$class][$objHash]->getEntities();
145
    }
146
147
    /**
148
     * Build a checksum from $primaryKey
149
     *
150
     * @param array $primaryKey
151
     * @return string
152
     */
153
    protected static function buildChecksum(array $primaryKey)
154
    {
155
        return md5(serialize($primaryKey));
156
    }
157
}
158