These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 const E_USER_DEPRECATED; |
||
10 | use function get_class; |
||
11 | use function sprintf; |
||
12 | use function trigger_error; |
||
13 | |||
14 | /** |
||
15 | * IncrementGenerator is responsible for generating auto increment identifiers. It uses |
||
16 | * a collection and generates the next id by using $inc on a field named "current_id". |
||
17 | * |
||
18 | * The 'collection' property determines which collection name is used to store the |
||
19 | * id values. If not specified it defaults to 'doctrine_increment_ids'. |
||
20 | * |
||
21 | * The 'key' property determines the document ID used to store the id values in the |
||
22 | * collection. If not specified it defaults to the name of the collection for the |
||
23 | * document. |
||
24 | * |
||
25 | * @final |
||
26 | */ |
||
27 | class IncrementGenerator extends AbstractIdGenerator |
||
28 | { |
||
29 | /** @var string|null */ |
||
30 | protected $collection = null; |
||
31 | |||
32 | /** @var string|null */ |
||
33 | protected $key = null; |
||
34 | |||
35 | /** @var int */ |
||
36 | protected $startingId = 1; |
||
37 | |||
38 | 11 | View Code Duplication | public function __construct() |
39 | { |
||
40 | 11 | if (self::class === static::class) { |
|
41 | 11 | return; |
|
42 | } |
||
43 | |||
44 | @trigger_error(sprintf('The class "%s" extends "%s" which will be final in MongoDB ODM 2.0.', static::class, self::class), E_USER_DEPRECATED); |
||
0 ignored issues
–
show
|
|||
45 | } |
||
46 | |||
47 | /** |
||
48 | * @param string $collection |
||
49 | */ |
||
50 | public function setCollection($collection) |
||
51 | { |
||
52 | $this->collection = $collection; |
||
53 | } |
||
54 | |||
55 | public function setKey(string $key) : void |
||
56 | { |
||
57 | $this->key = $key; |
||
58 | } |
||
59 | |||
60 | 2 | public function setStartingId(int $startingId) : void |
|
61 | { |
||
62 | 2 | $this->startingId = $startingId; |
|
63 | 2 | } |
|
64 | |||
65 | /** @inheritDoc */ |
||
66 | 11 | public function generate(DocumentManager $dm, object $document) |
|
67 | { |
||
68 | 11 | $className = get_class($document); |
|
69 | 11 | $db = $dm->getDocumentDatabase($className); |
|
70 | |||
71 | 11 | $key = $this->key ?: $dm->getDocumentCollection($className)->getCollectionName(); |
|
72 | 11 | $collectionName = $this->collection ?: 'doctrine_increment_ids'; |
|
73 | 11 | $collection = $db->selectCollection($collectionName); |
|
74 | |||
75 | /* |
||
76 | * Unable to use '$inc' and '$setOnInsert' together due to known bug. |
||
77 | * @see https://jira.mongodb.org/browse/SERVER-10711 |
||
78 | * Results in error: Cannot update 'current_id' and 'current_id' at the same time |
||
79 | */ |
||
80 | 11 | $query = ['_id' => $key, 'current_id' => ['$exists' => true]]; |
|
81 | 11 | $update = ['$inc' => ['current_id' => 1]]; |
|
82 | 11 | $options = ['upsert' => false, 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER]; |
|
83 | 11 | $result = $collection->findOneAndUpdate($query, $update, $options); |
|
84 | |||
85 | /* |
||
86 | * Updated nothing - counter doesn't exist, creating new counter. |
||
87 | * Not bothering with {$exists: false} in the criteria as that won't avoid |
||
88 | * an exception during a possible race condition. |
||
89 | */ |
||
90 | 11 | if ($result === null) { |
|
91 | 11 | $query = ['_id' => $key]; |
|
92 | 11 | $update = ['$inc' => ['current_id' => $this->startingId]]; |
|
93 | 11 | $options = ['upsert' => true, 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER]; |
|
94 | 11 | $collection->findOneAndUpdate($query, $update, $options); |
|
95 | |||
96 | 11 | return $this->startingId; |
|
97 | } |
||
98 | |||
99 | 5 | return $result['current_id'] ?? $this->startingId; |
|
100 | } |
||
101 | } |
||
102 |
If you suppress an error, we recommend checking for the error condition explicitly: