Skip to content

Commit cc42952

Browse files
committed
Add options to disable some transformations in the query builder
1 parent 1bef2de commit cc42952

File tree

1 file changed

+57
-13
lines changed

1 file changed

+57
-13
lines changed

src/Query/Builder.php

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,18 @@ class Builder extends BaseBuilder
123123
*/
124124
public $options = [];
125125

126+
public const TRANSFORM_QUERY_DATE = 1 << 0;
127+
public const TRANSFORM_RESULT_DATE = 1 << 1;
128+
public const TRANSFORM_RENAME_QUERY_ROOT_ID = 1 << 2;
129+
public const TRANSFORM_RENAME_RESULT_ROOT_ID = 1 << 3;
130+
public const TRANSFORM_RENAME_QUERY_EMBED_ID = 1 << 4;
131+
public const TRANSFORM_RENAME_RESULT_EMBED_ID = 1 << 5;
132+
133+
/** @var int-mask-of<self::TRANSFORM_* */
134+
private int $transformations = -1;
135+
126136
/**
127-
* All of the available clause operators.
137+
* All the available clause operators.
128138
*
129139
* @var array
130140
*/
@@ -575,6 +585,27 @@ public function generateCacheKey()
575585
return md5(serialize(array_values($key)));
576586
}
577587

588+
public function disableDateTransformation(): static
589+
{
590+
$this->transformations &= ~self::TRANSFORM_QUERY_DATE & ~self::TRANSFORM_RESULT_DATE;
591+
592+
return $this;
593+
}
594+
595+
public function disableRootIdTransformation(): static
596+
{
597+
$this->transformations &= ~self::TRANSFORM_RENAME_QUERY_ROOT_ID & ~self::TRANSFORM_RENAME_RESULT_ROOT_ID;
598+
599+
return $this;
600+
}
601+
602+
public function disableEmbedIdTransformation(): static
603+
{
604+
$this->transformations &= ~self::TRANSFORM_RENAME_QUERY_EMBED_ID & ~self::TRANSFORM_RENAME_RESULT_EMBED_ID;
605+
606+
return $this;
607+
}
608+
578609
/** @return ($function is null ? AggregationBuilder : mixed) */
579610
public function aggregate($function = null, $columns = ['*'])
580611
{
@@ -1763,9 +1794,12 @@ public function orWhereIntegerNotInRaw($column, $values, $boolean = 'and')
17631794
throw new BadMethodCallException('This method is not supported by MongoDB');
17641795
}
17651796

1766-
private function aliasIdForQuery(array $values): array
1797+
private function aliasIdForQuery(array $values, bool $root = true): array
17671798
{
1768-
if (array_key_exists('id', $values)) {
1799+
if (
1800+
($root && $this->transformations & self::TRANSFORM_RENAME_QUERY_ROOT_ID || ! $root && $this->transformations & self::TRANSFORM_RENAME_QUERY_EMBED_ID)
1801+
&& array_key_exists('id', $values)
1802+
) {
17691803
if (array_key_exists('_id', $values) && $values['id'] !== $values['_id']) {
17701804
throw new InvalidArgumentException('Cannot have both "id" and "_id" fields.');
17711805
}
@@ -1792,7 +1826,10 @@ private function aliasIdForQuery(array $values): array
17921826
}
17931827

17941828
// ".id" subfield are alias for "._id"
1795-
if (str_ends_with($key, '.id')) {
1829+
if (
1830+
$this->transformations & self::TRANSFORM_RENAME_QUERY_EMBED_ID
1831+
&& str_ends_with($key, '.id')
1832+
) {
17961833
$newkey = substr($key, 0, -3) . '._id';
17971834
if (array_key_exists($newkey, $values) && $value !== $values[$newkey]) {
17981835
throw new InvalidArgumentException(sprintf('Cannot have both "%s" and "%s" fields.', $key, $newkey));
@@ -1805,8 +1842,8 @@ private function aliasIdForQuery(array $values): array
18051842

18061843
foreach ($values as &$value) {
18071844
if (is_array($value)) {
1808-
$value = $this->aliasIdForQuery($value);
1809-
} elseif ($value instanceof DateTimeInterface) {
1845+
$value = $this->aliasIdForQuery($value, false);
1846+
} elseif ($this->transformations & self::TRANSFORM_QUERY_DATE && $value instanceof DateTimeInterface) {
18101847
$value = new UTCDateTime($value);
18111848
}
18121849
}
@@ -1817,42 +1854,49 @@ private function aliasIdForQuery(array $values): array
18171854
/**
18181855
* @internal
18191856
*
1857+
* @param bool $embed True when applied to a sub-document
18201858
* @psalm-param T $values
18211859
*
18221860
* @psalm-return T
18231861
*
18241862
* @template T of array|object
18251863
*/
1826-
public function aliasIdForResult(array|object $values): array|object
1864+
public function aliasIdForResult(array|object $values, bool $root = false): array|object
18271865
{
18281866
if (is_array($values)) {
1829-
if (array_key_exists('_id', $values) && ! array_key_exists('id', $values)) {
1867+
if (
1868+
($root && $this->transformations & self::TRANSFORM_RENAME_RESULT_ROOT_ID || ! $root && $this->transformations & self::TRANSFORM_RENAME_QUERY_EMBED_ID)
1869+
&& array_key_exists('_id', $values) && ! array_key_exists('id', $values)
1870+
) {
18301871
$values['id'] = $values['_id'];
18311872
unset($values['_id']);
18321873
}
18331874

18341875
foreach ($values as $key => $value) {
1835-
if ($value instanceof UTCDateTime) {
1876+
if ($this->transformations & self::TRANSFORM_RESULT_DATE && $value instanceof UTCDateTime) {
18361877
$values[$key] = Date::instance($value->toDateTime())
18371878
->setTimezone(new DateTimeZone(date_default_timezone_get()));
18381879
} elseif (is_array($value) || is_object($value)) {
1839-
$values[$key] = $this->aliasIdForResult($value);
1880+
$values[$key] = $this->aliasIdForResult($value, true);
18401881
}
18411882
}
18421883
}
18431884

18441885
if ($values instanceof stdClass) {
1845-
if (property_exists($values, '_id') && ! property_exists($values, 'id')) {
1886+
if (
1887+
($root && $this->transformations & self::TRANSFORM_RENAME_RESULT_ROOT_ID || ! $root && $this->transformations & self::TRANSFORM_RENAME_QUERY_EMBED_ID)
1888+
&& property_exists($values, '_id') && ! property_exists($values, 'id')
1889+
) {
18461890
$values->id = $values->_id;
18471891
unset($values->_id);
18481892
}
18491893

18501894
foreach (get_object_vars($values) as $key => $value) {
1851-
if ($value instanceof UTCDateTime) {
1895+
if ($this->transformations & self::TRANSFORM_RESULT_DATE && $value instanceof UTCDateTime) {
18521896
$values->{$key} = Date::instance($value->toDateTime())
18531897
->setTimezone(new DateTimeZone(date_default_timezone_get()));
18541898
} elseif (is_array($value) || is_object($value)) {
1855-
$values->{$key} = $this->aliasIdForResult($value);
1899+
$values->{$key} = $this->aliasIdForResult($value, true);
18561900
}
18571901
}
18581902
}

0 commit comments

Comments
 (0)