Completed
Pull Request — master (#1984)
by Maciej
19:41
created

IncrementGenerator::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 8
Ratio 100 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

Changes 0
Metric Value
dl 8
loc 8
ccs 3
cts 5
cp 0.6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.2559

1 Method

Rating   Name   Duplication   Size   Complexity  
A IncrementGenerator::setKey() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Id;
6
7
use Doctrine\ODM\MongoDB\DocumentManager;
8
use MongoDB\Operation\FindOneAndUpdate;
9
use function get_class;
10
11
/**
12
 * IncrementGenerator is responsible for generating auto increment identifiers. It uses
13
 * a collection and generates the next id by using $inc on a field named "current_id".
14
 *
15
 * The 'collection' property determines which collection name is used to store the
16
 * id values. If not specified it defaults to 'doctrine_increment_ids'.
17
 *
18
 * The 'key' property determines the document ID used to store the id values in the
19
 * collection. If not specified it defaults to the name of the collection for the
20
 * document.
21
 */
22
class IncrementGenerator extends AbstractIdGenerator
23
{
24
    /** @var string|null */
25
    protected $collection = null;
26
27
    /** @var string|null */
28
    protected $key = null;
29
30
    /** @var int */
31
    protected $startingId = 1;
32
33
    /**
34
     * @param string $collection
35
     */
36
    public function setCollection($collection)
37
    {
38
        $this->collection = $collection;
39
    }
40
41
    public function setKey(string $key) : void
42
    {
43
        $this->key = $key;
44
    }
45
46 2
    public function setStartingId(int $startingId) : void
47
    {
48 2
        $this->startingId = $startingId;
49 2
    }
50
51
    /** @inheritDoc */
52 11
    public function generate(DocumentManager $dm, object $document)
53
    {
54 11
        $className = get_class($document);
55 11
        $db        = $dm->getDocumentDatabase($className);
56
57 11
        $key            = $this->key ?: $dm->getDocumentCollection($className)->getCollectionName();
58 11
        $collectionName = $this->collection ?: 'doctrine_increment_ids';
59 11
        $collection     = $db->selectCollection($collectionName);
60
61
        /*
62
         * Unable to use '$inc' and '$setOnInsert' together due to known bug.
63
         * @see https://jira.mongodb.org/browse/SERVER-10711
64
         * Results in error: Cannot update 'current_id' and 'current_id' at the same time
65
         */
66 11
        $query   = ['_id' => $key, 'current_id' => ['$exists' => true]];
67 11
        $update  = ['$inc' => ['current_id' => 1]];
68 11
        $options = ['upsert' => false, 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER];
69 11
        $result  = $collection->findOneAndUpdate($query, $update, $options);
70
71
        /*
72
         * Updated nothing - counter doesn't exist, creating new counter.
73
         * Not bothering with {$exists: false} in the criteria as that won't avoid
74
         * an exception during a possible race condition.
75
         */
76 11
        if ($result === null) {
77 11
            $query   = ['_id' => $key];
78 11
            $update  = ['$inc' => ['current_id' => $this->startingId]];
79 11
            $options = ['upsert' => true, 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER];
80 11
            $collection->findOneAndUpdate($query, $update, $options);
81
82 11
            return $this->startingId;
83
        }
84
85 5
        return $result['current_id'] ?? $this->startingId;
86
    }
87
}
88