Skip to content

Commit

Permalink
PHPORM-229 Make Query\Builder return objects instead of array to matc…
Browse files Browse the repository at this point in the history
…h Laravel's behavior (#3107)
  • Loading branch information
GromNaN authored Aug 27, 2024
1 parent f1ffd1b commit ebda1fa
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 168 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.
## [5.0.0] - next

* **BREAKING CHANGE** Use `id` as an alias for `_id` in commands and queries for compatibility with Eloquent packages by @GromNaN in [#3040](https://github.com/mongodb/laravel-mongodb/pull/3040)
* **BREAKING CHANGE** Make Query\Builder return objects instead of array to match Laravel behavior by @GromNaN in [#3107](https://github.com/mongodb/laravel-mongodb/pull/3107)

## [4.8.0] - 2024-08-27

Expand Down
8 changes: 4 additions & 4 deletions docs/includes/query-builder/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,11 +531,11 @@ public function testUpsert(): void

$this->assertSame(2, $result);

$this->assertSame(119, DB::table('movies')->where('title', 'Inspector Maigret')->first()['runtime']);
$this->assertSame(false, DB::table('movies')->where('title', 'Inspector Maigret')->first()['recommended']);
$this->assertSame(119, DB::table('movies')->where('title', 'Inspector Maigret')->first()->runtime);
$this->assertSame(false, DB::table('movies')->where('title', 'Inspector Maigret')->first()->recommended);

$this->assertSame(true, DB::table('movies')->where('title', 'Petit Maman')->first()['recommended']);
$this->assertSame(72, DB::table('movies')->where('title', 'Petit Maman')->first()['runtime']);
$this->assertSame(true, DB::table('movies')->where('title', 'Petit Maman')->first()->recommended);
$this->assertSame(72, DB::table('movies')->where('title', 'Petit Maman')->first()->runtime);
}

public function testUpdateUpsert(): void
Expand Down
47 changes: 36 additions & 11 deletions src/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use MongoDB\Driver\Cursor;
use Override;
use RuntimeException;
use stdClass;

use function array_fill_keys;
use function array_is_list;
Expand All @@ -45,18 +46,21 @@
use function func_get_args;
use function func_num_args;
use function get_debug_type;
use function get_object_vars;
use function implode;
use function in_array;
use function is_array;
use function is_bool;
use function is_callable;
use function is_float;
use function is_int;
use function is_object;
use function is_string;
use function md5;
use function preg_match;
use function preg_quote;
use function preg_replace;
use function property_exists;
use function serialize;
use function sprintf;
use function str_ends_with;
Expand Down Expand Up @@ -391,7 +395,7 @@ public function toMql(): array
}

$options = [
'typeMap' => ['root' => 'array', 'document' => 'array'],
'typeMap' => ['root' => 'object', 'document' => 'array'],
];

// Add custom query options
Expand Down Expand Up @@ -450,8 +454,7 @@ public function toMql(): array
$options['projection'] = $projection;
}

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

// Add custom query options
if (count($this->options)) {
Expand Down Expand Up @@ -516,7 +519,7 @@ public function getFresh($columns = [], $returnLazy = false)
}

foreach ($result as &$document) {
if (is_array($document)) {
if (is_array($document) || is_object($document)) {
$document = $this->aliasIdForResult($document);
}
}
Expand Down Expand Up @@ -1641,16 +1644,38 @@ private function aliasIdForQuery(array $values): array
return $values;
}

private function aliasIdForResult(array $values): array
/**
* @psalm-param T $values
*
* @psalm-return T
*
* @template T of array|object
*/
private function aliasIdForResult(array|object $values): array|object
{
if (array_key_exists('_id', $values) && ! array_key_exists('id', $values)) {
$values['id'] = $values['_id'];
//unset($values['_id']);
if (is_array($values)) {
if (array_key_exists('_id', $values) && ! array_key_exists('id', $values)) {
$values['id'] = $values['_id'];
//unset($values['_id']);
}

foreach ($values as $key => $value) {
if (is_array($value) || is_object($value)) {
$values[$key] = $this->aliasIdForResult($value);
}
}
}

foreach ($values as $key => $value) {
if (is_array($value)) {
$values[$key] = $this->aliasIdForResult($value);
if ($values instanceof stdClass) {
if (property_exists($values, '_id') && ! property_exists($values, 'id')) {
$values->id = $values->_id;
//unset($values->_id);
}

foreach (get_object_vars($values) as $key => $value) {
if (is_array($value) || is_object($value)) {
$values->{$key} = $this->aliasIdForResult($value);
}
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/Queue/Failed/MongoFailedJobProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public function log($connection, $queue, $payload, $exception)
*/
public function all()
{
$all = $this->getTable()->orderBy('_id', 'desc')->get()->all();
$all = $this->getTable()->orderBy('id', 'desc')->get()->all();

$all = array_map(function ($job) {
$job['id'] = (string) $job['_id'];
$job->id = (string) $job->id;

return (object) $job;
return $job;
}, $all);

return $all;
Expand All @@ -69,9 +69,9 @@ public function find($id)
return null;
}

$job['id'] = (string) $job['_id'];
$job->id = (string) $job->id;

return (object) $job;
return $job;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Queue/MongoQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ protected function releaseJobsThatHaveBeenReservedTooLong($queue)
->get();

foreach ($reserved as $job) {
$this->releaseJob($job['_id'], $job['attempts']);
$this->releaseJob($job->id, $job->attempts);
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/AuthTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ function ($actualUser, $actualToken) use ($user, &$token) {

$this->assertEquals(1, DB::table('password_reset_tokens')->count());
$reminder = DB::table('password_reset_tokens')->first();
$this->assertEquals('[email protected]', $reminder['email']);
$this->assertNotNull($reminder['token']);
$this->assertInstanceOf(UTCDateTime::class, $reminder['created_at']);
$this->assertEquals('[email protected]', $reminder->email);
$this->assertNotNull($reminder->token);
$this->assertInstanceOf(UTCDateTime::class, $reminder->created_at);

$credentials = [
'email' => '[email protected]',
Expand Down
4 changes: 2 additions & 2 deletions tests/Query/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ public function testMql(array $expected, Closure $build, ?string $requiredMethod

// Operations that return a Cursor expect a "typeMap" option.
if (isset($expected['find'][1])) {
$expected['find'][1]['typeMap'] = ['root' => 'array', 'document' => 'array'];
$expected['find'][1]['typeMap'] = ['root' => 'object', 'document' => 'array'];
}

if (isset($expected['aggregate'][1])) {
$expected['aggregate'][1]['typeMap'] = ['root' => 'array', 'document' => 'array'];
$expected['aggregate'][1]['typeMap'] = ['root' => 'object', 'document' => 'array'];
}

// Compare with assertEquals because the query can contain BSON objects.
Expand Down
Loading

0 comments on commit ebda1fa

Please sign in to comment.