Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
139450da
Commit
139450da
authored
Dec 01, 2013
by
Klimov Paul
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Mongo condition composition reworked to match original DB interface.
parent
27a1c63e
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
222 additions
and
135 deletions
+222
-135
Collection.php
extensions/mongo/Collection.php
+215
-34
Query.php
extensions/mongo/Query.php
+0
-44
QueryTest.php
tests/unit/extensions/mongo/QueryTest.php
+7
-57
No files found.
extensions/mongo/Collection.php
View file @
139450da
...
...
@@ -214,75 +214,255 @@ class Collection extends Object
protected
function
normalizeConditionKeyword
(
$key
)
{
static
$map
=
[
'
or
'
=>
'$or'
,
'
OR
'
=>
'$or'
,
'>'
=>
'$gt'
,
'>='
=>
'$gte'
,
'<'
=>
'$lt'
,
'<='
=>
'$lte'
,
'!='
=>
'$ne'
,
'<>'
=>
'$ne'
,
'
in
'
=>
'$in'
,
'
not in
'
=>
'$nin'
,
'
all
'
=>
'$all'
,
'
size
'
=>
'$size'
,
'
type
'
=>
'$type'
,
'
exists
'
=>
'$exists'
,
'
notexists
'
=>
'$exists'
,
'
elemmatch
'
=>
'$elemMatch'
,
'
mod
'
=>
'$mod'
,
'
IN
'
=>
'$in'
,
'
NOT IN
'
=>
'$nin'
,
'
ALL
'
=>
'$all'
,
'
SIZE
'
=>
'$size'
,
'
TYPE
'
=>
'$type'
,
'
EXISTS
'
=>
'$exists'
,
'
NOTEXISTS
'
=>
'$exists'
,
'
ELEMMATCH
'
=>
'$elemMatch'
,
'
MOD
'
=>
'$mod'
,
'%'
=>
'$mod'
,
'='
=>
'$$eq'
,
'=='
=>
'$$eq'
,
'
where
'
=>
'$where'
'
WHERE
'
=>
'$where'
];
$
key
=
strtolow
er
(
$key
);
if
(
array_key_exists
(
$
k
ey
,
$map
))
{
return
$map
[
$
k
ey
];
$
matchKey
=
strtoupp
er
(
$key
);
if
(
array_key_exists
(
$
matchK
ey
,
$map
))
{
return
$map
[
$
matchK
ey
];
}
else
{
return
$key
;
}
}
/**
* Builds up Mongo condition from user friendly condition.
* @param array $condition raw condition.
* @return array normalized Mongo condition.
* @throws \yii\base\InvalidParamException on invalid condition given.
* Converts given value into [[MongoId]] instance.
* If array given, each element of it will be processed.
* @param mixed $rawId raw id(s).
* @return array|\MongoId normalized id(s).
*/
protected
function
ensureMongoId
(
$rawId
)
{
if
(
is_array
(
$rawId
))
{
$result
=
[];
foreach
(
$rawId
as
$key
=>
$value
)
{
$result
[
$key
]
=
$this
->
ensureMongoId
(
$value
);
}
return
$result
;
}
elseif
(
is_object
(
$rawId
))
{
if
(
$rawId
instanceof
\MongoId
)
{
return
$rawId
;
}
else
{
$rawId
=
(
string
)
$rawId
;
}
}
return
new
\MongoId
(
$rawId
);
}
/**
* Parses the condition specification and generates the corresponding Mongo condition.
* @param array $condition the condition specification. Please refer to [[Query::where()]]
* on how to specify a condition.
* @return array the generated Mongo condition
* @throws InvalidParamException if the condition is in bad format
*/
public
function
buildCondition
(
$condition
)
{
static
$builders
=
[
'AND'
=>
'buildAndCondition'
,
'OR'
=>
'buildOrCondition'
,
'BETWEEN'
=>
'buildBetweenCondition'
,
'NOT BETWEEN'
=>
'buildBetweenCondition'
,
'IN'
=>
'buildInCondition'
,
'NOT IN'
=>
'buildInCondition'
,
'LIKE'
=>
'buildLikeCondition'
,
];
if
(
!
is_array
(
$condition
))
{
throw
new
InvalidParamException
(
'Condition should be an array.'
);
}
elseif
(
empty
(
$condition
))
{
return
[];
}
if
(
isset
(
$condition
[
0
]))
{
// operator format: operator, operand 1, operand 2, ...
$operator
=
strtoupper
(
$condition
[
0
]);
if
(
isset
(
$builders
[
$operator
]))
{
$method
=
$builders
[
$operator
];
array_shift
(
$condition
);
return
$this
->
$method
(
$operator
,
$condition
);
}
else
{
throw
new
InvalidParamException
(
'Found unknown operator in query: '
.
$operator
);
}
}
else
{
// hash format: 'column1' => 'value1', 'column2' => 'value2', ...
return
$this
->
buildHashCondition
(
$condition
);
}
}
/**
* Creates a condition based on column-value pairs.
* @param array $condition the condition specification.
* @return array the generated Mongo condition.
*/
public
function
buildHashCondition
(
$condition
)
{
$result
=
[];
foreach
(
$condition
as
$key
=>
$value
)
{
foreach
(
$condition
as
$name
=>
$value
)
{
$name
=
$this
->
normalizeConditionKeyword
(
$name
);
if
(
strncmp
(
'$'
,
$name
,
1
)
===
0
)
{
// Native Mongo condition:
$result
[
$name
]
=
$value
;
}
else
{
if
(
is_array
(
$value
))
{
$actualValue
=
$this
->
buildCondition
(
$value
);
if
(
array_key_exists
(
0
,
$value
))
{
// Quick IN condition:
$result
=
array_merge
(
$result
,
$this
->
buildInCondition
(
'IN'
,
[
$name
,
$value
]));
}
else
{
$actualValue
=
$value
;
// Normalize possible verbose condition:
$actualValue
=
[];
foreach
(
$value
as
$k
=>
$v
)
{
$actualValue
[
$this
->
normalizeConditionKeyword
(
$k
)]
=
$v
;
}
$result
[
$name
]
=
$actualValue
;
}
if
(
is_numeric
(
$key
))
{
$result
[]
=
$actualValue
;
}
else
{
$key
=
$this
->
normalizeConditionKeyword
(
$key
);
if
(
strncmp
(
'$'
,
$key
,
1
)
!==
0
&&
is_array
(
$actualValue
)
&&
array_key_exists
(
0
,
$actualValue
))
{
// shortcut for IN condition
if
(
$key
==
'_id'
)
{
foreach
(
$actualValue
as
&
$actualValuePart
)
{
if
(
!
is_object
(
$actualValuePart
))
{
$actualValuePart
=
new
\MongoId
(
$actualValuePart
);
// Direct match:
if
(
$name
==
'_id'
)
{
$value
=
$this
->
ensureMongoId
(
$value
);
}
$result
[
$name
]
=
$value
;
}
}
}
return
$result
;
}
/**
* Connects two or more conditions with the `AND` operator.
* @param string $operator the operator to use for connecting the given operands
* @param array $operands the Mongo conditions to connect.
* @return array the generated Mongo condition.
*/
public
function
buildAndCondition
(
$operator
,
$operands
)
{
$result
=
[];
foreach
(
$operands
as
$operand
)
{
$condition
=
$this
->
buildCondition
(
$operand
);
$result
=
array_merge_recursive
(
$result
,
$condition
);
}
$result
[
$key
][
'$in'
]
=
$actualValue
;
return
$result
;
}
/**
* Connects two or more conditions with the `OR` operator.
* @param string $operator the operator to use for connecting the given operands
* @param array $operands the Mongo conditions to connect.
* @return array the generated Mongo condition.
*/
public
function
buildOrCondition
(
$operator
,
$operands
)
{
$operator
=
$this
->
normalizeConditionKeyword
(
$operator
);
$parts
=
[];
foreach
(
$operands
as
$operand
)
{
$parts
[]
=
$this
->
buildCondition
(
$operand
);
}
return
[
$operator
=>
$parts
];
}
/**
* Creates an Mongo condition, which emulates the `BETWEEN` operator.
* @param string $operator the operator to use
* @param array $operands the first operand is the column name. The second and third operands
* describe the interval that column value should be in.
* @return array the generated Mongo condition.
* @throws InvalidParamException if wrong number of operands have been given.
*/
public
function
buildBetweenCondition
(
$operator
,
$operands
)
{
if
(
!
isset
(
$operands
[
0
],
$operands
[
1
],
$operands
[
2
]))
{
throw
new
InvalidParamException
(
"Operator '
$operator
' requires three operands."
);
}
list
(
$column
,
$value1
,
$value2
)
=
$operands
;
if
(
strncmp
(
'NOT'
,
$operator
,
3
)
===
0
)
{
return
[
$column
=>
[
'$lt'
=>
$value1
,
'$gt'
=>
$value2
,
]
];
}
else
{
if
(
$key
==
'_id'
&&
!
is_object
(
$actualValue
))
{
$actualValue
=
new
\MongoId
(
$actualValue
);
return
[
$column
=>
[
'$gte'
=>
$value1
,
'$lte'
=>
$value2
,
]
];
}
}
/**
* Creates an Mongo condition with the `IN` operator.
* @param string $operator the operator to use (e.g. `IN` or `NOT IN`)
* @param array $operands the first operand is the column name. If it is an array
* a composite IN condition will be generated.
* The second operand is an array of values that column value should be among.
* @return array the generated Mongo condition.
* @throws InvalidParamException if wrong number of operands have been given.
*/
public
function
buildInCondition
(
$operator
,
$operands
)
{
if
(
!
isset
(
$operands
[
0
],
$operands
[
1
]))
{
throw
new
InvalidParamException
(
"Operator '
$operator
' requires two operands."
);
}
$result
[
$key
]
=
$actualValue
;
list
(
$column
,
$values
)
=
$operands
;
$values
=
(
array
)
$values
;
if
(
!
is_array
(
$column
))
{
$columns
=
[
$column
];
$values
=
[
$column
=>
$values
];
}
elseif
(
count
(
$column
)
<
2
)
{
$columns
=
$column
;
$values
=
[
$column
[
0
]
=>
$values
];
}
else
{
$columns
=
$column
;
}
$operator
=
$this
->
normalizeConditionKeyword
(
$operator
);
$result
=
[];
foreach
(
$columns
as
$column
)
{
if
(
$column
==
'_id'
)
{
$inValues
=
$this
->
ensureMongoId
(
$values
[
$column
]);
}
else
{
$inValues
=
$values
[
$column
];
}
$result
[
$column
][
$operator
]
=
$inValues
;
}
return
$result
;
}
/**
* Creates a Mongo condition, which emulates the `LIKE` operator.
* @param string $operator the operator to use
* @param array $operands the first operand is the column name.
* The second operand is a single value that column value should be compared with.
* @return array the generated Mongo condition.
* @throws InvalidParamException if wrong number of operands have been given.
*/
public
function
buildLikeCondition
(
$operator
,
$operands
)
{
if
(
!
isset
(
$operands
[
0
],
$operands
[
1
]))
{
throw
new
InvalidParamException
(
"Operator '
$operator
' requires two operands."
);
}
list
(
$column
,
$value
)
=
$operands
;
return
[
$column
=>
'/'
.
$value
.
'/'
];
}
}
\ No newline at end of file
extensions/mongo/Query.php
View file @
139450da
...
...
@@ -74,50 +74,6 @@ class Query extends Component implements QueryInterface
}
/**
* Adds an additional WHERE condition to the existing one.
* The new condition and the existing one will be joined using the 'AND' operator.
* @param array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see where()
* @see orWhere()
*/
public
function
andWhere
(
$condition
)
{
if
(
is_array
(
$this
->
where
))
{
$this
->
where
=
array_merge
(
$this
->
where
,
$condition
);
}
else
{
$this
->
where
=
$condition
;
}
return
$this
;
}
/**
* Adds an additional WHERE condition to the existing one.
* The new condition and the existing one will be joined using the 'OR' operator.
* @param array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see where()
* @see andWhere()
*/
public
function
orWhere
(
$condition
)
{
if
(
is_array
(
$this
->
where
))
{
if
(
array_key_exists
(
'or'
,
$this
->
where
)
&&
count
(
$this
->
where
)
==
1
)
{
$this
->
where
[
'or'
][]
=
$condition
;
}
else
{
$this
->
where
=
[
'or'
=>
[
$this
->
where
,
$condition
]
];
}
}
else
{
$this
->
where
=
$condition
;
}
return
$this
;
}
/**
* @param Connection $db the database connection used to execute the query.
* @return \MongoCursor mongo cursor instance.
*/
...
...
tests/unit/extensions/mongo/QueryTest.php
View file @
139450da
...
...
@@ -45,8 +45,9 @@ class QueryTest extends MongoTestCase
$query
->
andWhere
([
'address'
=>
'address1'
]);
$this
->
assertEquals
(
[
'name'
=>
'name1'
,
'address'
=>
'address1'
'and'
,
[
'name'
=>
'name1'
],
[
'address'
=>
'address1'
]
],
$query
->
where
);
...
...
@@ -54,65 +55,14 @@ class QueryTest extends MongoTestCase
$query
->
orWhere
([
'name'
=>
'name2'
]);
$this
->
assertEquals
(
[
'or'
=>
[
'or'
,
[
'name'
=>
'name1'
,
'address'
=>
'address1'
'and'
,
[
'name'
=>
'name1'
],
[
'address'
=>
'address1'
]
],
[
'name'
=>
'name2'
]
]
],
$query
->
where
);
$query
->
orWhere
([
'name'
=>
'name3'
]);
$this
->
assertEquals
(
[
'or'
=>
[
[
'name'
=>
'name1'
,
'address'
=>
'address1'
],
[
'name'
=>
'name2'
],
[
'name'
=>
'name3'
]
]
],
$query
->
where
);
$query
->
andWhere
([
'address'
=>
'address2'
]);
$this
->
assertEquals
(
[
'or'
=>
[
[
'name'
=>
'name1'
,
'address'
=>
'address1'
],
[
'name'
=>
'name2'
],
[
'name'
=>
'name3'
]
],
'address'
=>
'address2'
],
$query
->
where
);
$query
->
orWhere
([
'name'
=>
'name4'
]);
$this
->
assertEquals
(
[
'or'
=>
[
[
'or'
=>
[
[
'name'
=>
'name1'
,
'address'
=>
'address1'
],
[
'name'
=>
'name2'
],
[
'name'
=>
'name3'
]
],
'address'
=>
'address2'
],
[
'name'
=>
'name4'
]
],
],
$query
->
where
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment