Completed
Push — feature/evo-2472-whoami ( 843346...066c1c )
by
unknown
83:53 queued 67:03
created

DocumentModel::findAll()   C

Complexity

Conditions 9
Paths 64

Size

Total Lines 66
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 13.8122

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 66
rs 6.4099
ccs 25
cts 41
cp 0.6098
cc 9
eloc 37
nc 64
nop 2
crap 13.8122

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Use doctrine odm as backend
4
 */
5
6
namespace Graviton\RestBundle\Model;
7
8
use Doctrine\ODM\MongoDB\DocumentRepository;
9
use Graviton\SchemaBundle\Model\SchemaModel;
10
use Symfony\Component\HttpFoundation\Request;
11
use Doctrine\ODM\MongoDB\Query\Builder;
12
use Graviton\Rql\Visitor\MongoOdm as Visitor;
13
use Xiag\Rql\Parser\Query;
14
use Graviton\ExceptionBundle\Exception\RecordOriginModifiedException;
15
16
/**
17
 * Use doctrine odm as backend
18
 *
19
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
20
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
21
 * @link     http://swisscom.ch
22
 */
23
class DocumentModel extends SchemaModel implements ModelInterface
24
{
25
    /**
26
     * @var string
27
     */
28
    protected $description;
29
    /**
30
     * @var string[]
31
     */
32
    protected $fieldTitles;
33
    /**
34
     * @var string[]
35
     */
36
    protected $fieldDescriptions;
37
    /**
38
     * @var string[]
39
     */
40
    protected $requiredFields = array();
41
    /**
42
     * @var DocumentRepository
43
     */
44
    private $repository;
45
    /**
46
     * @var Visitor
47
     */
48
    private $visitor;
49
    /**
50
     * @var array
51
     */
52
    protected $notModifiableOriginRecords;
53
    /**
54
     * @var  integer
55
     */
56
    private $paginationDefaultLimit;
57
58
    /**
59
     * @var boolean
60
     */
61
    protected $filterByAuthUser;
62
63
    /**
64
     * @var string
65
     */
66
    protected $filterByAuthField;
67
68
    /**
69
     * @param Visitor $visitor                    rql query visitor
70
     * @param array   $notModifiableOriginRecords strings with not modifiable recordOrigin values
71
     * @param integer $paginationDefaultLimit     amount of data records to be returned when in pagination context.
72
     */
73 2
    public function __construct(Visitor $visitor, $notModifiableOriginRecords, $paginationDefaultLimit)
74
    {
75 2
        parent::__construct();
76 2
        $this->visitor = $visitor;
77 2
        $this->notModifiableOriginRecords = $notModifiableOriginRecords;
78 2
        $this->paginationDefaultLimit = (int) $paginationDefaultLimit;
79 2
    }
80
81
    /**
82
     * get repository instance
83
     *
84
     * @return DocumentRepository
85
     */
86
    public function getRepository()
87
    {
88
        return $this->repository;
89
    }
90
91
    /**
92
     * create new app model
93
     *
94
     * @param DocumentRepository $repository Repository of countries
95
     *
96
     * @return \Graviton\RestBundle\Model\DocumentModel
97
     */
98 2
    public function setRepository(DocumentRepository $repository)
99
    {
100 2
        $this->repository = $repository;
101
102 2
        return $this;
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     *
108
     * @param Request $request The request object
109
     * @param Object  $user    The user
110
     *
111
     * @return array
112
     */
113 1
    public function findAll(Request $request, $user = false)
114
    {
115 1
        $pageNumber = $request->query->get('page', 1);
116 1
        $numberPerPage = (int) $request->query->get('perPage', $this->getDefaultLimit());
117 1
        $startAt = ($pageNumber - 1) * $numberPerPage;
118
119
        /** @var \Doctrine\ODM\MongoDB\Query\Builder $queryBuilder */
120 1
        $queryBuilder = $this->repository
121 1
            ->createQueryBuilder();
122
123 1
        if ($this->filterByAuthUser && $user && $user->getId()) {
124
            $queryBuilder->field($this->filterByAuthField)->equals($user->getId());
125
        }
126
127
        // *** do we have an RQL expression, do we need to filter data?
128 1
        if ($request->attributes->get('hasRql', false)) {
129
            $queryBuilder = $this->doRqlQuery(
130
                $queryBuilder,
131
                $request->attributes->get('rqlQuery')
132
            );
133
        } else {
134
            // @todo [lapistano]: seems the offset is missing for this query.
135
            /** @var \Doctrine\ODM\MongoDB\Query\Builder $qb */
136 1
            $queryBuilder->find($this->repository->getDocumentName());
137
        }
138
139
        // define offset and limit
140 1
        if (!array_key_exists('skip', $queryBuilder->getQuery()->getQuery())) {
141 1
            $queryBuilder->skip($startAt);
0 ignored issues
show
Bug introduced by
The method skip does only exist in Doctrine\ODM\MongoDB\Query\Builder, but not in Doctrine\ODM\MongoDB\Query\Expr.

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...
142 1
        } else {
143
            $startAt = (int) $queryBuilder->getQuery()->getQuery()['skip'];
144
        }
145
146 1
        if (!array_key_exists('limit', $queryBuilder->getQuery()->getQuery())) {
147 1
            $queryBuilder->limit($numberPerPage);
0 ignored issues
show
Bug introduced by
The method limit does only exist in Doctrine\ODM\MongoDB\Query\Builder, but not in Doctrine\ODM\MongoDB\Query\Expr.

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...
148 1
        } else {
149
            $numberPerPage = (int) $queryBuilder->getQuery()->getQuery()['limit'];
150
        }
151
152
        /**
153
         * add a default sort on id if none was specified earlier
154
         *
155
         * not specifying something to sort on leads to very weird cases when fetching references
156
         */
157 1
        if (!array_key_exists('sort', $queryBuilder->getQuery()->getQuery())) {
158 1
            $queryBuilder->sort('_id');
159 1
        }
160
161
        // run query
162 1
        $query = $queryBuilder->getQuery();
163 1
        $records = array_values($query->execute()->toArray());
164
165 1
        $totalCount = $query->count();
166 1
        $numPages = (int) ceil($totalCount / $numberPerPage);
167 1
        $page = (int) ceil($startAt / $numberPerPage) + 1;
168 1
        if ($numPages > 1) {
169
            $request->attributes->set('paging', true);
170
            $request->attributes->set('page', $page);
171
            $request->attributes->set('numPages', $numPages);
172
            $request->attributes->set('startAt', $startAt);
173
            $request->attributes->set('perPage', $numberPerPage);
174
            $request->attributes->set('totalCount', $totalCount);
175
        }
176
177 1
        return $records;
178
    }
179
180
    /**
181
     * @param \Graviton\I18nBundle\Document\Translatable $entity entity to insert
182
     *
183
     * @return Object
184
     */
185 View Code Duplication
    public function insertRecord($entity)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
186
    {
187
        $this->checkIfOriginRecord($entity);
188
        $manager = $this->repository->getDocumentManager();
189
        $manager->persist($entity);
190
        $manager->flush($entity);
191
192
        return $this->find($entity->getId());
193
    }
194
195
    /**
196
     * @param string $documentId id of entity to find
197
     *
198
     * @return Object
199
     */
200 1
    public function find($documentId)
201
    {
202 1
        return $this->repository->find($documentId);
203
    }
204
205
    /**
206
     * {@inheritDoc}
207
     *
208
     * @param string $documentId id of entity to update
209
     * @param Object $entity     new entity
210
     *
211
     * @return Object
212
     */
213 1 View Code Duplication
    public function updateRecord($documentId, $entity)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
214
    {
215 1
        $manager = $this->repository->getDocumentManager();
216
        // In both cases the document attribute named originRecord must not be 'core'
217 1
        $this->checkIfOriginRecord($entity);
218 1
        $this->checkIfOriginRecord($this->find($documentId));
219 1
        $entity = $manager->merge($entity);
220 1
        $manager->flush();
221
222 1
        return $entity;
223
    }
224
225
    /**
226
     * {@inheritDoc}
227
     *
228
     * @param string $documentId id of entity to delete
229
     *
230
     * @return null|Object
231
     */
232 1
    public function deleteRecord($documentId)
233
    {
234 1
        $manager = $this->repository->getDocumentManager();
235 1
        $entity = $this->find($documentId);
236
237 1
        $return = $entity;
238 1
        if ($entity) {
239 1
            $this->checkIfOriginRecord($entity);
240 1
            $manager->remove($entity);
241 1
            $manager->flush();
242 1
            $return = null;
243 1
        }
244
245 1
        return $return;
246
    }
247
248
    /**
249
     * get classname of entity
250
     *
251
     * @return string
252
     */
253 1
    public function getEntityClass()
254
    {
255 1
        return $this->repository->getDocumentName();
256
    }
257
258
    /**
259
     * {@inheritDoc}
260
     *
261
     * Currently this is being used to build the route id used for redirecting
262
     * to newly made documents. It might benefit from having a different name
263
     * for those purposes.
264
     *
265
     * We might use a convention based mapping here:
266
     * Graviton\CoreBundle\Document\App -> mongodb://graviton_core
267
     * Graviton\CoreBundle\Entity\Table -> mysql://graviton_core
268
     *
269
     * @todo implement this in a more convention based manner
270
     *
271
     * @return string
272
     */
273
    public function getConnectionName()
274
    {
275
        $bundle = strtolower(substr(explode('\\', get_class($this))[1], 0, -6));
276
277
        return 'graviton.' . $bundle;
278
    }
279
280
    /**
281
     * Does the actual query using the RQL Bundle.
282
     *
283
     * @param Builder $queryBuilder Doctrine ODM QueryBuilder
284
     * @param Query   $query        query from parser
285
     *
286
     * @return array
287
     */
288
    protected function doRqlQuery($queryBuilder, Query $query)
289
    {
290
        $this->visitor->setBuilder($queryBuilder);
291
292
        return $this->visitor->visit($query);
293
    }
294
295
    /**
296
     * Checks the recordOrigin attribute of a record and will throw an exception if value is not allowed
297
     *
298
     * @param Object $record record
299
     *
300
     * @return void
301
     */
302 7
    protected function checkIfOriginRecord($record)
303
    {
304
        if ($record instanceof RecordOriginInterface
305 7
            && !$record->isRecordOriginModifiable()
306 7
        ) {
307 3
            $values = $this->notModifiableOriginRecords;
308 3
            $originValue = strtolower(trim($record->getRecordOrigin()));
309
310 3
            if (in_array($originValue, $values)) {
311 1
                $msg = sprintf("Must not be one of the following keywords: %s", implode(', ', $values));
312
313 1
                throw new RecordOriginModifiedException($msg);
314
            }
315 2
        }
316 6
    }
317
318
    /**
319
     * Determines the configured amount fo data records to be returned in pagination context.
320
     *
321
     * @return int
322
     */
323 1
    private function getDefaultLimit()
324
    {
325 1
        if (0 < $this->paginationDefaultLimit) {
326 1
            return $this->paginationDefaultLimit;
327
        }
328
329
        return 10;
330
    }
331
332
    /**
333
     * @param Boolean $active active
334
     * @param String  $field  field
335 2
     * @return void
336
     */
337 2
    public function setFilterByAuthUser($active, $field)
338 2
    {
339 2
        $this->filterByAuthUser = is_bool($active) ? $active : false;
340
        $this->filterByAuthField = $field;
341
    }
342
}
343