DocumentRepository::findAll()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Doctrine\ODM\CouchDB;
4
5
use Doctrine\Common\Persistence\ObjectRepository;
6
7
/**
8
 * An DocumentRepository serves as a repository for documents with generic as well as
9
 * business specific methods for retrieving documents.
10
 *
11
 * This class is designed for inheritance and users can subclass this class to
12
 * write their own repositories with business-specific methods to locate documents.
13
 *
14
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
15
 * @link        www.doctrine-project.com
16
 * @since       1.0
17
 * @author      Jonathan H. Wage <[email protected]>
18
 * @author      Roman Borschel <[email protected]>
19
 */
20
class DocumentRepository implements ObjectRepository
21
{
22
    /**
23
     * @var string
24
     */
25
    protected $documentName;
26
27
    /**
28
     * @var string
29
     */
30
    protected $documentType;
31
32
    /**
33
     * @var DocumentManager
34
     */
35
    protected $dm;
36
37
    /**
38
     * @var Mapping\ClassMetadata
39
     */
40
    protected $class;
41
42
    /**
43
     * Initializes a new <tt>DocumentRepository</tt>.
44
     *
45
     * @param DocumentManager $dm The DocumentManager to use.
46
     * @param Mapping\ClassMetadata $class The class descriptor.
47
     */
48
    public function __construct($dm, Mapping\ClassMetadata $class)
49
    {
50
        $this->documentName = $class->name;
51
        $this->documentType = str_replace("\\", ".", $this->documentName);
52
        $this->dm = $dm;
53
        $this->class = $class;
54
    }
55
56
    /**
57
     * Find a single document by its identifier
58
     *
59
     * @param mixed $id A single identifier or an array of criteria.
60
     * @return object|null $document
61
     */
62
    public function find($id)
63
    {
64
        $uow = $this->dm->getUnitOfWork();
65
66
        $document = $uow->tryGetById($id);
67
68
        if ($document === false) {
69
            $response = $this->dm->getCouchDBClient()->findDocument($id);
70
            if ($response->status == 404) {
71
                return null;
72
            }
73
74
            $hints = array();
75
            $document = $uow->createDocument($this->documentName, $response->body, $hints);
76
        }
77
78
        return $document;
79
    }
80
81
    /**
82
     * @param  object $document
83
     * @return void
84
     */
85
    final public function refresh($document)
86
    {
87
        $uow = $this->dm->getUnitOfWork();
88
        $uow->refresh($document);
89
    }
90
91
    /**
92
     * Find Many documents of the given repositories type by id.
93
     *
94
     * @param array $ids
95
     * @param null|int $limit
96
     * @param null|int $offset
97
     * @return array
98
     */
99
    public function findMany(array $ids, $limit = null, $offset = null)
100
    {
101
        $uow = $this->dm->getUnitOfWork();
102
        return $uow->findMany($ids, $this->documentName, $limit, $offset);
103
    }
104
105
    public function findAll()
106
    {
107
        return $this->dm->createQuery('doctrine_repositories', 'type_constraint')
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Doctrine\CouchDB\View\Query as the method toArray() does only exist in the following sub-classes of Doctrine\CouchDB\View\Query: Doctrine\ODM\CouchDB\View\ODMQuery. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
108
                        ->setKey($this->documentType)
109
                        ->setIncludeDocs(true)
110
                        ->toArray(true)
111
                        ->execute();
112
    }
113
114
    public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
115
    {
116
        if (count($criteria) == 1) {
117
            foreach ($criteria AS $field => $value) {
118
                $query = $this->dm->createQuery('doctrine_repositories', 'equal_constraint')
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Doctrine\CouchDB\View\Query as the method toArray() does only exist in the following sub-classes of Doctrine\CouchDB\View\Query: Doctrine\ODM\CouchDB\View\ODMQuery. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
119
                                  ->setKey(array($this->documentType, $field, $value))
120
                                  ->setIncludeDocs(true)
121
                                  ->toArray(true);
122
                if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
123
                   $query->setLimit($limit);
124
                }
125
                if ($offset) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $offset of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
126
                   $query->setSkip($offset);
127
                }
128
                return $query->execute();
129
            }
130
        } else {
131
            $ids = array();
132
            $num = 0;
133
            foreach ($criteria AS $field => $value) {
134
                $ids[$num] = array();
135
                $result = $this->dm->createNativeQuery('doctrine_repositories', 'equal_constraint')
136
                                   ->setKey(array($this->documentType, $field, $value))
137
                                   ->execute();
138
                foreach ($result aS $doc) {
139
                    $ids[$num][] = $doc['id'];
140
                }
141
                $num++;
142
            }
143
            $mergeIds = $ids[0];
144
            for ($i = 1; $i < $num; $i++) {
145
                $mergeIds = array_intersect($mergeIds, $ids[$i]);
146
            }
147
148
            return $this->findMany(array_values($mergeIds), $limit, $offset);
149
        }
150
    }
151
152
    public function findOneBy(array $criteria)
153
    {
154
        $docs = $this->findBy($criteria);
155
        return isset($docs[0]) ? $docs[0] : null;
156
    }
157
158
    /**
159
     * @return string
160
     */
161
    public function getDocumentName()
162
    {
163
        return $this->documentName;
164
    }
165
166
    /**
167
     * @return DocumentManager
168
     */
169
    public function getDocumentManager()
170
    {
171
        return $this->dm;
172
    }
173
174
    /**
175
     * @return Mapping\ClassMetadata
176
     */
177
    public function getClassMetadata()
178
    {
179
        return $this->class;
180
    }
181
182
    public function getClassName()
183
    {
184
        return $this->getDocumentName();
185
    }
186
}
187