Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 82847b7

Browse files
committed
V5
Query Builder return stdClass: https://github.com/laravel/framework/blob/213a370b703592587bafcd52d38a0ad772ff7442/src/Illuminate/Database/Connection.php#L118C16-L118C25 Alias id for _id everywhere Don't expose _id field: No _id attribute in Eloquent. Deprecate reading and writing _id attribute. Always convert datetime to UTCDateTime: https://github.com/laravel/framework/blob/213a370b703592587bafcd52d38a0ad772ff7442/src/Illuminate/Database/Connection.php#L733-L734 Timezone : using Carbon instead of system timezone.
1 parent 6a5124f commit 82847b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+693
-676
lines changed

‎docs/includes/fundamentals/aggregation/AggregationsBuilderTest.php‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public function testAggregationBuilderSortStage(): void
6868
// end aggregation sort stage
6969

7070
$this->assertEquals(6, $result->count());
71-
$this->assertEquals('Janet Doe', $result->first()['name']);
71+
$this->assertEquals('Janet Doe', $result->first()->name);
7272
}
7373

7474
public function testAggregationBuilderProjectStage(): void
@@ -80,8 +80,9 @@ public function testAggregationBuilderProjectStage(): void
8080
// end aggregation project stage
8181

8282
$this->assertEquals(6, $result->count());
83-
$this->assertNotNull($result->first()['name']);
84-
$this->assertArrayNotHasKey('_id', $result->first());
83+
$this->assertNotNull($result->first()->name);
84+
$this->assertObjectNotHasProperty('_id', $result->first());
85+
$this->assertObjectNotHasProperty('id', $result->first());
8586
}
8687

8788
public function testAggregationBuilderPipeline(): void
@@ -104,7 +105,7 @@ public function testAggregationBuilderPipeline(): void
104105
$result = $pipeline->get();
105106

106107
$this->assertEquals(2, $result->count());
107-
$this->assertNotNull($result->first()['birth_year_avg']);
108+
$this->assertNotNull($result->first()->birth_year_avg);
108109
}
109110

110111
// phpcs:disable Squiz.Commenting.FunctionComment.WrongStyle
@@ -130,6 +131,6 @@ public function testCustomOperatorFactory(): void
130131
$result = $pipeline->get();
131132

132133
$this->assertEquals(6, $result->count());
133-
$this->assertNotNull($result->first()['birth_year']);
134+
$this->assertNotNull($result->first()->birth_year);
134135
}
135136
}

‎src/Auth/User.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@ class User extends BaseUser
1111
{
1212
use DocumentModel;
1313

14-
protected $primaryKey = '_id';
1514
protected $keyType = 'string';
1615
}

‎src/Collection.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Exception;
88
use MongoDB\BSON\ObjectID;
9+
use MongoDB\BSON\UTCDateTime;
910
use MongoDB\Collection as MongoCollection;
1011

1112
use function array_walk_recursive;

‎src/Eloquent/Builder.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public function raw($value = null)
191191
}
192192

193193
// The result is a single object.
194-
if (is_array($results) && array_key_exists('_id', $results)) {
194+
if (is_array($results) && array_key_exists('id', $results)) {
195195
return $this->model->newFromBuilder((array) $results);
196196
}
197197

‎src/Eloquent/DocumentModel.php‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ public function getIdAttribute($value = null)
7676
{
7777
// If we don't have a value for 'id', we will use the MongoDB '_id' value.
7878
// This allows us to work with models in a more sql-like way.
79-
if (! $value && array_key_exists('_id', $this->attributes)) {
80-
$value = $this->attributes['_id'];
79+
if (! $value && array_key_exists('id', $this->attributes)) {
80+
$value = $this->attributes['id'];
8181
}
8282

8383
// Convert ObjectID to string.
@@ -238,8 +238,8 @@ public function setAttribute($key, $value)
238238
};
239239
}
240240

241-
// Convert _id to ObjectID.
242-
if ($key === '_id' && is_string($value)) {
241+
// Convert "id" to ObjectID.
242+
if ($key === 'id' && is_string($value)) {
243243
$builder = $this->newBaseQueryBuilder();
244244

245245
$value = $builder->convertKey($value);
@@ -721,9 +721,9 @@ protected function isBSON(mixed $value): bool
721721
public function save(array $options = [])
722722
{
723723
// SQL databases would use autoincrement the id field if set to null.
724-
// Apply the same behavior to MongoDB with _id only, otherwise null would be stored.
725-
if (array_key_exists('_id', $this->attributes) && $this->attributes['_id'] === null) {
726-
unset($this->attributes['_id']);
724+
// Apply the same behavior to MongoDB with "id" only, otherwise null would be stored.
725+
if (array_key_exists('id', $this->attributes) && $this->attributes['id'] === null) {
726+
unset($this->attributes['id']);
727727
}
728728

729729
$saved = parent::save($options);

‎src/Eloquent/Model.php‎

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ abstract class Model extends BaseModel
1616
{
1717
use DocumentModel;
1818

19-
/**
20-
* The primary key for the model.
21-
*
22-
* @var string
23-
*/
24-
protected $primaryKey = '_id';
25-
2619
/**
2720
* The primary key type.
2821
*

‎src/MongoDBQueueServiceProvider.php‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace MongoDB\Laravel;
66

7+
use Illuminate\Queue\Failed\DatabaseFailedJobProvider;
78
use Illuminate\Queue\Failed\NullFailedJobProvider;
89
use Illuminate\Queue\QueueServiceProvider;
910
use MongoDB\Laravel\Queue\Failed\MongoFailedJobProvider;
@@ -52,14 +53,14 @@ protected function registerFailedJobServices()
5253
/**
5354
* Create a new MongoDB failed job provider.
5455
*/
55-
protected function mongoFailedJobProvider(array $config): MongoFailedJobProvider
56+
protected function mongoFailedJobProvider(array $config): DatabaseFailedJobProvider
5657
{
5758
if (! isset($config['collection']) && isset($config['table'])) {
5859
trigger_error('Since mongodb/laravel-mongodb 4.4: Using "table" option for the queue is deprecated. Use "collection" instead.', E_USER_DEPRECATED);
5960
$config['collection'] = $config['table'];
6061
}
6162

62-
return new MongoFailedJobProvider(
63+
return new DatabaseFailedJobProvider(
6364
$this->app['db'],
6465
$config['database'] ?? null,
6566
$config['collection'] ?? 'failed_jobs',

‎src/Query/AggregationBuilder.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private function execute(array $options): CursorInterface&Iterator
8888
$pipeline = $encoder->encode($this->getPipeline());
8989

9090
$options = array_replace(
91-
['typeMap' => ['root' => 'array', 'document' => 'array']],
91+
['typeMap' => ['root' => 'object', 'document' => 'object']],
9292
$this->options,
9393
$options,
9494
);

‎src/Query/Builder.php‎

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use ArgumentCountError;
88
use BadMethodCallException;
9+
use Carbon\CarbonImmutable;
910
use Carbon\CarbonPeriod;
1011
use Closure;
1112
use DateTimeInterface;
@@ -25,6 +26,7 @@
2526
use MongoDB\Driver\Cursor;
2627
use Override;
2728
use RuntimeException;
29+
use stdClass;
2830

2931
use function array_fill_keys;
3032
use function array_is_list;
@@ -39,20 +41,23 @@
3941
use function call_user_func_array;
4042
use function count;
4143
use function ctype_xdigit;
44+
use function date_default_timezone_get;
4245
use function dd;
4346
use function dump;
4447
use function end;
4548
use function explode;
4649
use function func_get_args;
4750
use function func_num_args;
4851
use function get_debug_type;
52+
use function get_object_vars;
4953
use function implode;
5054
use function in_array;
5155
use function is_array;
5256
use function is_bool;
5357
use function is_callable;
5458
use function is_float;
5559
use function is_int;
60+
use function is_object;
5661
use function is_string;
5762
use function md5;
5863
use function preg_match;
@@ -227,7 +232,7 @@ public function hint($index)
227232
/** @inheritdoc */
228233
public function find($id, $columns = [])
229234
{
230-
return $this->where('_id', '=', $this->convertKey($id))->first($columns);
235+
return $this->where('id', '=', $this->convertKey($id))->first($columns);
231236
}
232237

233238
/** @inheritdoc */
@@ -391,7 +396,7 @@ public function toMql(): array
391396
}
392397

393398
$options = [
394-
'typeMap' => ['root' => 'array', 'document' => 'array'],
399+
'typeMap' => ['root' => 'object', 'document' => 'array'],
395400
];
396401

397402
// Add custom query options
@@ -451,7 +456,7 @@ public function toMql(): array
451456
}
452457

453458
// Fix for legacy support, converts the results to arrays instead of objects.
454-
$options['typeMap'] = ['root' => 'array', 'document' => 'array'];
459+
$options['typeMap'] = ['root' => 'object', 'document' => 'array'];
455460

456461
// Add custom query options
457462
if (count($this->options)) {
@@ -506,7 +511,7 @@ public function getFresh($columns = [], $returnLazy = false)
506511
if ($returnLazy) {
507512
return LazyCollection::make(function () use ($result) {
508513
foreach ($result as $item) {
509-
yield $this->aliasIdForResult($item);
514+
yield is_object($item) ? $this->aliasIdForResult($item) : $item;
510515
}
511516
});
512517
}
@@ -515,8 +520,8 @@ public function getFresh($columns = [], $returnLazy = false)
515520
$result = $result->toArray();
516521
}
517522

518-
foreach ($result as &$document) {
519-
$document = $this->aliasIdForResult($document);
523+
foreach ($result as &$item) {
524+
$item = is_object($item) ? $this->aliasIdForResult($item) : $item;
520525
}
521526

522527
return new Collection($result);
@@ -590,7 +595,7 @@ public function aggregate($function = null, $columns = ['*'])
590595
if (isset($results[0])) {
591596
$result = (array) $results[0];
592597

593-
return $result['aggregate'];
598+
return $this->aliasIdForResult($result['aggregate']);
594599
}
595600
}
596601

@@ -628,6 +633,7 @@ public function orderBy($column, $direction = 'asc')
628633
}
629634

630635
$column = (string) $column;
636+
631637
if ($column === 'natural') {
632638
$this->orders['$natural'] = $direction;
633639
} else {
@@ -692,10 +698,9 @@ public function insert(array $values)
692698
if (isset($document['_id']) && $document['_id'] !== $document['id']) {
693699
throw new InvalidArgumentException('Cannot insert document with different "id" and "_id" values');
694700
}
695-
696-
$document['_id'] = $document['id'];
697-
unset($document['id']);
698701
}
702+
703+
$document = $this->aliasIdForQuery($document);
699704
}
700705

701706
$options = $this->inheritConnectionOptions();
@@ -710,6 +715,8 @@ public function insertGetId(array $values, $sequence = null)
710715
{
711716
$options = $this->inheritConnectionOptions();
712717

718+
$values = $this->aliasIdForQuery($values);
719+
713720
$result = $this->collection->insertOne($values, $options);
714721

715722
if (! $result->isAcknowledged()) {
@@ -735,13 +742,6 @@ public function update(array $values, array $options = [])
735742
unset($values[$key]);
736743
}
737744

738-
// Since "id" is an alias for "_id", we prevent updating it
739-
foreach ($values as $fields) {
740-
if (array_key_exists('id', $fields)) {
741-
throw new InvalidArgumentException('Cannot update "id" field.');
742-
}
743-
}
744-
745745
return $this->performUpdate($values, $options);
746746
}
747747

@@ -778,9 +778,9 @@ public function pluck($column, $key = null)
778778
$results = $this->get($key === null ? [$column] : [$column, $key]);
779779

780780
// Convert ObjectID's to strings
781-
if (((string) $key) === '_id') {
781+
if (((string) $key) === 'id') {
782782
$results = $results->map(function ($item) {
783-
$item['_id'] = (string) $item['_id'];
783+
$item->id = (string) $item->id;
784784

785785
return $item;
786786
});
@@ -798,13 +798,14 @@ public function delete($id = null)
798798
// the ID to allow developers to simply and quickly remove a single row
799799
// from their database without manually specifying the where clauses.
800800
if ($id !== null) {
801-
$this->where('_id', '=', $id);
801+
$this->where('id', '=', $id);
802802
}
803803

804804
$wheres = $this->compileWheres();
805805
$options = $this->inheritConnectionOptions();
806806

807-
if (is_int($this->limit)) {
807+
/** 1000 is a large value used by Laravel {@see DatabaseFailedJobProvider} */
808+
if (is_int($this->limit) && $this->limit !== 1000) {
808809
if ($this->limit !== 1) {
809810
throw new LogicException(sprintf('Delete limit can be 1 or null (unlimited). Got %d', $this->limit));
810811
}
@@ -997,15 +998,19 @@ protected function performUpdate(array $update, array $options = [])
997998
}
998999

9991000
// Since "id" is an alias for "_id", we prevent updating it
1000-
foreach ($update as $operator => $fields) {
1001+
foreach ($update as &$fields) {
10011002
if (array_key_exists('id', $fields)) {
10021003
throw new InvalidArgumentException('Cannot update "id" field.');
10031004
}
1005+
1006+
// Rename "id" to "_id" for embedded documents
1007+
$fields = $this->aliasIdForQuery($fields);
10041008
}
10051009

10061010
$options = $this->inheritConnectionOptions($options);
10071011

10081012
$wheres = $this->compileWheres();
1013+
10091014
$result = $this->collection->updateMany($wheres, $update, $options);
10101015
if ($result->isAcknowledged()) {
10111016
return $result->getModifiedCount() ? $result->getModifiedCount() : $result->getUpsertedCount();
@@ -1188,7 +1193,7 @@ protected function compileWheres(): array
11881193
}
11891194
}
11901195

1191-
return $compiled;
1196+
return $this->aliasIdForQuery($compiled);
11921197
}
11931198

11941199
protected function compileWhereBasic(array $where): array
@@ -1561,13 +1566,52 @@ private function aliasIdForQuery(array $values): array
15611566
unset($values['id']);
15621567
}
15631568

1569+
foreach ($values as $key => $value) {
1570+
if (is_string($key) && str_ends_with($key, '.id')) {
1571+
$values[substr($key, 0, -3) . '._id'] = $value;
1572+
unset($values[$key]);
1573+
}
1574+
}
1575+
1576+
foreach ($values as &$value) {
1577+
if ($value instanceof DateTimeInterface) {
1578+
$value = new UTCDateTime($value);
1579+
} elseif (is_array($value)) {
1580+
$value = $this->aliasIdForQuery($value);
1581+
}
1582+
}
1583+
15641584
return $values;
15651585
}
15661586

1567-
private function aliasIdForResult(array $values): array
1587+
private function aliasIdForResult(stdClass|array $values): stdClass|array
15681588
{
1569-
if (isset($values['_id'])) {
1570-
$values['id'] = $values['_id'];
1589+
if (is_array($values)) {
1590+
if (isset($values['_id'])) {
1591+
$values['id'] = $values['_id'];
1592+
unset($values['_id']);
1593+
}
1594+
1595+
foreach ($values as $key => $value) {
1596+
if ($value instanceof UTCDateTime) {
1597+
$values[$key] = CarbonImmutable::createFromTimestamp($value->toDateTime()->getTimestamp(), 'UTC')->setTimezone(date_default_timezone_get());
1598+
} elseif (is_array($value) || $value instanceof stdClass) {
1599+
$values[$key] = $this->aliasIdForResult($value);
1600+
}
1601+
}
1602+
} else {
1603+
if (isset($values->_id)) {
1604+
$values->id = $values->_id;
1605+
unset($values->_id);
1606+
}
1607+
1608+
foreach (get_object_vars($values) as $key => $value) {
1609+
if ($value instanceof UTCDateTime) {
1610+
$values->{$key} = CarbonImmutable::createFromTimestamp($value->toDateTime()->getTimestamp(), 'UTC')->setTimezone(date_default_timezone_get());
1611+
} elseif (is_array($value) || $value instanceof stdClass) {
1612+
$values->{$key} = $this->aliasIdForResult($value);
1613+
}
1614+
}
15711615
}
15721616

15731617
return $values;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /