ProxyQuery   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 2
dl 0
loc 137
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A __call() 0 4 1
A __clone() 0 4 1
A execute() 0 28 4
A setSortBy() 0 4 1
A getSortBy() 0 4 1
A setSortOrder() 0 4 1
A getSortOrder() 0 4 1
A getSingleScalarResult() 0 6 1
A getQueryBuilder() 0 4 1
A setFirstResult() 0 5 1
A getFirstResult() 0 4 1
A setMaxResults() 0 7 1
A getMaxResults() 0 4 1
A getUniqueParameterId() 0 4 1
A entityJoin() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\DoctrineMongoDBAdminBundle\Datagrid;
15
16
use Doctrine\ODM\MongoDB\Query\Builder;
17
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
18
19
/**
20
 * This class try to unify the query usage with Doctrine.
21
 */
22
class ProxyQuery implements ProxyQueryInterface
23
{
24
    /**
25
     * @var Builder
26
     */
27
    protected $queryBuilder;
28
29
    /**
30
     * @var array
31
     */
32
    protected $sortBy;
33
34
    /**
35
     * @var string
36
     */
37
    protected $sortOrder;
38
39
    /**
40
     * @var int|null
41
     */
42
    protected $firstResult;
43
44
    /**
45
     * @var int|null
46
     */
47
    protected $maxResults;
48
49
    public function __construct(Builder $queryBuilder)
50
    {
51
        $this->queryBuilder = $queryBuilder;
52
    }
53
54
    public function __call($name, $args)
55
    {
56
        return \call_user_func_array([$this->queryBuilder, $name], $args);
57
    }
58
59
    public function __clone()
60
    {
61
        $this->queryBuilder = clone $this->queryBuilder;
62
    }
63
64
    public function execute(array $params = [], $hydrationMode = null)
65
    {
66
        if ([] !== $params || null !== $hydrationMode) {
67
            // NEXT_MAJOR : remove the `trigger_error()` call and uncomment the exception
68
            @trigger_error(sprintf(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
69
                'Passing a value different than an empty array as argument 1 or "null" as argument 2 for "%s()" is'
70
                .' deprecated since sonata-project/doctrine-mongodb-admin-bundle 3.x and will throw an exception'
71
                .' in 4.0. The values provided in this array are not used.',
72
                __METHOD__
73
            ), E_USER_DEPRECATED);
74
75
            // throw new \InvalidArgumentException(sprintf(
76
            //    'No arguments must be passed to "%s()".'
77
            //    __METHOD__
78
            // ));
79
        }
80
81
        // always clone the original queryBuilder.
82
        $queryBuilder = clone $this->queryBuilder;
83
84
        // todo : check how doctrine behave, potential SQL injection here ...
85
        $sortBy = $this->getSortBy();
86
        if ($sortBy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sortBy of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
87
            $queryBuilder->sort($sortBy, $this->getSortOrder());
88
        }
89
90
        return $queryBuilder->getQuery()->execute();
91
    }
92
93
    public function setSortBy($parentAssociationMappings, $fieldMapping): void
94
    {
95
        $this->sortBy = $fieldMapping['fieldName'];
96
    }
97
98
    public function getSortBy()
99
    {
100
        return $this->sortBy;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sortBy; (array) is incompatible with the return type declared by the interface Sonata\AdminBundle\Datag...eryInterface::getSortBy of type string.

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...
101
    }
102
103
    public function setSortOrder($sortOrder): void
104
    {
105
        $this->sortOrder = $sortOrder;
106
    }
107
108
    public function getSortOrder()
109
    {
110
        return $this->sortOrder;
111
    }
112
113
    public function getSingleScalarResult()
114
    {
115
        $query = $this->queryBuilder->getQuery();
116
117
        return $query->getSingleResult();
118
    }
119
120
    public function getQueryBuilder()
121
    {
122
        return $this->queryBuilder;
123
    }
124
125
    public function setFirstResult($firstResult): void
126
    {
127
        $this->firstResult = $firstResult;
128
        $this->queryBuilder->skip($firstResult ?? 0);
129
    }
130
131
    public function getFirstResult()
132
    {
133
        return $this->firstResult;
134
    }
135
136
    public function setMaxResults($maxResults): void
137
    {
138
        $this->maxResults = $maxResults;
139
140
        // @see https://docs.mongodb.com/manual/reference/method/cursor.limit/#zero-value
141
        $this->queryBuilder->limit($maxResults ?? 0);
142
    }
143
144
    public function getMaxResults()
145
    {
146
        return $this->maxResults;
147
    }
148
149
    public function getUniqueParameterId()
150
    {
151
        // TODO: Implement getUniqueParameterId() method.
152
    }
153
154
    public function entityJoin(array $associationMappings)
155
    {
156
        // TODO: Implement entityJoin() method.
157
    }
158
}
159