Completed
Push — master ( e02aed...4992bd )
by Iqbal
02:36
created

Repository::reset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
/*
3
 * This file is part of the Borobudur-Cqrs package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\Cqrs\ReadModel\Repository;
12
13
use Borobudur\Bus\Message\MessageMapperTrait;
14
use Borobudur\Cqrs\Collection;
15
use Borobudur\Cqrs\Exception\InvalidArgumentException;
16
use Borobudur\Cqrs\ReadModel\ReadModelInterface;
17
use Borobudur\Cqrs\ReadModel\Repository\Scope\ScopeInterface;
18
use Borobudur\Cqrs\ReadModel\Storage\Finder\FinderInterface;
19
use Borobudur\Cqrs\ReadModel\Storage\StorageInterface;
20
21
/**
22
 * @author      Iqbal Maulana <[email protected]>
23
 * @created     8/19/15
24
 */
25
class Repository implements RepositoryInterface
26
{
27
    use MessageMapperTrait;
28
29
    /**
30
     * @var StorageInterface
31
     */
32
    private $storage;
33
34
    /**
35
     * @var string
36
     */
37
    private $table;
38
39
    /**
40
     * @var string
41
     */
42
    private $class;
43
44
    /**
45
     * @var FinderInterface
46
     */
47
    private $finder;
48
49
    /**
50
     * Constructor.
51
     *
52
     * @param StorageInterface $storage
53
     * @param string           $table
54
     * @param string           $class
55
     */
56
    public function __construct(StorageInterface $storage, $table, $class)
57
    {
58
        $this->storage = $storage;
59
        $this->table = $table;
60
        $this->class = $class;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function save(ReadModelInterface $model)
67
    {
68
        $this->assertSameInstance($model);
69
        $this->storage->save($model, $this->table);
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    public function count()
76
    {
77
        return $this->finder()->count();
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    public function findById($id)
84
    {
85
        return $this->addCriteria(array('id' => $id))->first();
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function scopes(array $scopes)
92
    {
93
        foreach ($scopes as $scope) {
94
            $this->scope($scope);
95
        }
96
97
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Borobudur\Cqrs\ReadModel\Repository\Repository) is incompatible with the return type declared by the interface Borobudur\Cqrs\ReadModel...sitoryInterface::scopes of type Borobudur\Cqrs\ReadModel\ReadModelInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function scope(ScopeInterface $scope)
104
    {
105
        $scope->scoping($this->finder());
106
107
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Borobudur\Cqrs\ReadModel\Repository\Repository) is incompatible with the return type declared by the interface Borobudur\Cqrs\ReadModel...ositoryInterface::scope of type Borobudur\Cqrs\ReadModel\ReadModelInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function findOne(array $fields)
114
    {
115
        return $this->addCriteria($fields)->first();
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function find(array $fields)
122
    {
123
        return $this->addCriteria($fields)->get();
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function findAll()
130
    {
131
        return $this->get();
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function remove($id)
138
    {
139
        $this->storage->remove($id, $this->table);
140
    }
141
142
    /*
143
     * {@inheritdoc}
144
     */
145
    public function reset()
146
    {
147
        $this->finder = null;
148
149
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Borobudur\Cqrs\ReadModel\Repository\Repository) is incompatible with the return type declared by the interface Borobudur\Cqrs\ReadModel...ositoryInterface::reset of type Borobudur\Cqrs\ReadModel\ReadModelInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
150
    }
151
152
    /**
153
     * Get finder that used for find data with complex criteria.
154
     *
155
     * @return FinderInterface
156
     */
157
    protected function finder()
158
    {
159
        if (null === $this->finder) {
160
            $this->finder = $this->storage->finder($this->table, $this->class);
161
        }
162
163
        return $this->finder;
164
    }
165
166
    /**
167
     * Add criteria.
168
     *
169
     * @param array $fields
170
     *
171
     * @return static
172
     */
173
    protected function addCriteria(array $fields)
174
    {
175
        foreach ($fields as $field => $value) {
176
            $this->finder()->where($this->finder()->expr()->equal($field, $value));
177
        }
178
179
        return $this;
180
    }
181
182
    /**
183
     * Get a collection.
184
     *
185
     * @return Collection
186
     */
187
    protected function get()
188
    {
189
        $results = $this->finder()->get();
190
        $this->reset();
191
192
        return $results;
193
    }
194
195
    /**
196
     * Find first record.
197
     *
198
     * @return ReadModelInterface
199
     */
200
    protected function first()
201
    {
202
        $result = $this->finder()->limit(1)->first();
203
        $this->reset();
204
205
        return $result;
206
    }
207
208
    /**
209
     * Assert that read model instance should be same.
210
     *
211
     * @param ReadModelInterface $model
212
     */
213
    protected function assertSameInstance(ReadModelInterface $model)
214
    {
215
        if (ltrim($this->class, '\\') !== ltrim(get_class($model), '\\')) {
216
            throw new InvalidArgumentException(sprintf(
217
                'Repository "%s" only accept read model "%s", but got "%s".',
218
                get_called_class(),
219
                $this->class,
220
                get_class($model)
221
            ));
222
        }
223
    }
224
}
225