|
4 | 4 |
|
5 | 5 | namespace MongoDB\Laravel\Eloquent; |
6 | 6 |
|
| 7 | +use Illuminate\Database\Eloquent\Builder; |
7 | 8 | use Illuminate\Database\Eloquent\Model as BaseModel; |
8 | 9 | use MongoDB\Laravel\Auth\User; |
9 | 10 |
|
@@ -57,4 +58,62 @@ final public static function isDocumentModel(string|object $class): bool |
57 | 58 | // Document models must use the DocumentModel trait. |
58 | 59 | return self::$documentModelClasses[$class] = array_key_exists(DocumentModel::class, class_uses_recursive($class)); |
59 | 60 | } |
| 61 | + |
| 62 | + /** |
| 63 | + * Override of Laravel's performInsert() to handle MongoDB _id immutability. |
| 64 | + * |
| 65 | + * Ensures syncOriginal() is called immediately after insert, so that |
| 66 | + * subsequent save() calls (e.g., inside the "created" model event) |
| 67 | + * don't treat the primary key (_id) as dirty. |
| 68 | + * |
| 69 | + * @param Builder $query |
| 70 | + * |
| 71 | + * @return bool |
| 72 | + */ |
| 73 | + protected function performInsert(Builder $query) |
| 74 | + { |
| 75 | + if ($this->usesUniqueIds()) { |
| 76 | + $this->setUniqueIds(); |
| 77 | + } |
| 78 | + |
| 79 | + if ($this->fireModelEvent('creating') === false) { |
| 80 | + return false; |
| 81 | + } |
| 82 | + |
| 83 | + // First we'll need to create a fresh query instance and touch the creation and |
| 84 | + // update timestamps on this model, which are maintained by us for developer |
| 85 | + // convenience. After, we will just continue saving these model instances. |
| 86 | + if ($this->usesTimestamps()) { |
| 87 | + $this->updateTimestamps(); |
| 88 | + } |
| 89 | + |
| 90 | + // If the model has an incrementing key, we can use the "insertGetId" method on |
| 91 | + // the query builder, which will give us back the final inserted ID for this |
| 92 | + // table from the database. Not all tables have to be incrementing though. |
| 93 | + $attributes = $this->getAttributesForInsert(); |
| 94 | + |
| 95 | + if ($this->getIncrementing()) { |
| 96 | + $this->insertAndSetId($query, $attributes); |
| 97 | + } else { |
| 98 | + if (empty($attributes)) { |
| 99 | + return true; |
| 100 | + } |
| 101 | + |
| 102 | + $query->insert($attributes); |
| 103 | + } |
| 104 | + |
| 105 | + // MongoDB-specific fix: prevent _id from being considered dirty after insert |
| 106 | + $this->syncOriginal(); |
| 107 | + |
| 108 | + // We will go ahead and set the exists property to true, so that it is set when |
| 109 | + // the created event is fired, just in case the developer tries to update it |
| 110 | + // during the event. This will allow them to do so and run an update here. |
| 111 | + $this->exists = true; |
| 112 | + |
| 113 | + $this->wasRecentlyCreated = true; |
| 114 | + |
| 115 | + $this->fireModelEvent('created', false); |
| 116 | + |
| 117 | + return true; |
| 118 | + } |
60 | 119 | } |
0 commit comments