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
8542448f
Commit
8542448f
authored
Nov 22, 2013
by
Carsten Brandt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactored redis AR to relect the latest changes
- make use of traits - short array - better implementation of query findByPk
parent
bc4324c0
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
402 additions
and
1065 deletions
+402
-1065
ActiveQuery.php
framework/yii/redis/ActiveQuery.php
+196
-568
ActiveRecord.php
framework/yii/redis/ActiveRecord.php
+107
-183
ActiveRelation.php
framework/yii/redis/ActiveRelation.php
+16
-238
LuaScriptBuilder.php
framework/yii/redis/LuaScriptBuilder.php
+11
-11
RecordSchema.php
framework/yii/redis/RecordSchema.php
+1
-1
Customer.php
tests/unit/data/ar/redis/Customer.php
+2
-2
Item.php
tests/unit/data/ar/redis/Item.php
+6
-5
Order.php
tests/unit/data/ar/redis/Order.php
+7
-7
OrderItem.php
tests/unit/data/ar/redis/OrderItem.php
+3
-3
ActiveRecordTest.php
tests/unit/framework/redis/ActiveRecordTest.php
+49
-46
RedisConnectionTest.php
tests/unit/framework/redis/RedisConnectionTest.php
+3
-0
RedisTestCase.php
tests/unit/framework/redis/RedisTestCase.php
+1
-1
No files found.
framework/yii/redis/ActiveQuery.php
View file @
8542448f
...
...
@@ -6,7 +6,11 @@
*/
namespace
yii\redis
;
use
yii\base\InvalidParamException
;
use
yii\base\NotSupportedException
;
use
yii\db\ActiveQueryInterface
;
use
yii\db\ActiveQueryTrait
;
use
yii\db\QueryTrait
;
/**
* ActiveQuery represents a query associated with an Active Record class.
...
...
@@ -43,91 +47,24 @@ use yii\base\NotSupportedException;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class
ActiveQuery
extends
\yii\base\Component
class
ActiveQuery
extends
\yii\base\Component
implements
ActiveQueryInterface
{
/**
* Sort ascending
* @see orderBy
*/
const
SORT_ASC
=
false
;
/**
* Sort descending
* @see orderBy
*/
const
SORT_DESC
=
true
;
/**
* @var string the name of the ActiveRecord class.
*/
public
$modelClass
;
/**
* @var array list of relations that this query should be performed with
*/
public
$with
;
/**
* @var string|callable $column the name of the column by which the query results should be indexed by.
* This can also be a callable (e.g. anonymous function) that returns the index value based on the given
* row or model data. For more details, see [[indexBy()]].
*/
public
$indexBy
;
/**
* @var boolean whether to return each record as an array. If false (default), an object
* of [[modelClass]] will be created to represent each record.
*/
public
$asArray
;
/**
* @var array the query condition.
* @see where()
*/
public
$where
;
/**
* @var integer maximum number of records to be returned. If not set or less than 0, it means no limit.
*/
public
$limit
;
/**
* @var integer zero-based offset from where the records are to be returned.
* If not set, it means starting from the beginning.
* If less than zero it means starting n elements from the end.
*/
public
$offset
;
/**
* @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement.
* The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which
* can be either [[ActiveQuery::SORT_ASC]] or [[ActiveQuery::SORT_DESC]]. The array may also contain [[Expression]] objects.
* If that is the case, the expressions will be converted into strings without any change.
*/
public
$orderBy
;
use
QueryTrait
;
use
ActiveQueryTrait
;
/**
* PHP magic method.
* This method allows calling static method defined in [[modelClass]] via this query object.
* It is mainly implemented for supporting the feature of scope.
* @param string $name the method name to be called
* @param array $params the parameters passed to the method
* @return mixed the method return result
* Executes the query and returns all results as an array.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return ActiveRecord[] the query results. If the query results in nothing, an empty array will be returned.
*/
public
function
__call
(
$name
,
$params
)
{
if
(
method_exists
(
$this
->
modelClass
,
$name
))
{
array_unshift
(
$params
,
$this
);
call_user_func_array
(
array
(
$this
->
modelClass
,
$name
),
$params
);
return
$this
;
}
else
{
return
parent
::
__call
(
$name
,
$params
);
}
}
/**
* Executes query and returns all results as an array.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
public
function
all
()
public
function
all
(
$db
=
null
)
{
// TODO add support for orderBy
$data
=
$this
->
executeScript
(
'All'
);
$rows
=
array
()
;
$data
=
$this
->
executeScript
(
$db
,
'All'
);
$rows
=
[]
;
foreach
(
$data
as
$dataRow
)
{
$row
=
array
()
;
$row
=
[]
;
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
$row
[
$dataRow
[
$i
++
]]
=
$dataRow
[
$i
++
];
...
...
@@ -137,28 +74,30 @@ class ActiveQuery extends \yii\base\Component
if
(
!
empty
(
$rows
))
{
$models
=
$this
->
createModels
(
$rows
);
if
(
!
empty
(
$this
->
with
))
{
$this
->
populateRelations
(
$models
,
$this
->
with
);
$this
->
findWith
(
$this
->
with
,
$models
);
}
return
$models
;
}
else
{
return
array
()
;
return
[]
;
}
}
/**
* Executes query and returns a single row of result.
* Executes the query and returns a single row of result.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
* the query result may be either an array or an ActiveRecord object. Null will be returned
* if the query results in nothing.
*/
public
function
one
()
public
function
one
(
$db
=
null
)
{
// TODO add support for orderBy
$data
=
$this
->
executeScript
(
'One'
);
if
(
$data
===
array
(
))
{
$data
=
$this
->
executeScript
(
$db
,
'One'
);
if
(
empty
(
$data
))
{
return
null
;
}
$row
=
array
()
;
$row
=
[]
;
$c
=
count
(
$data
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
$row
[
$data
[
$i
++
]]
=
$data
[
$i
++
];
...
...
@@ -166,584 +105,273 @@ class ActiveQuery extends \yii\base\Component
if
(
$this
->
asArray
)
{
$model
=
$row
;
}
else
{
/** @var
$class ActiveRecord
*/
/** @var
ActiveRecord $class
*/
$class
=
$this
->
modelClass
;
$model
=
$class
::
create
(
$row
);
}
if
(
!
empty
(
$this
->
with
))
{
$models
=
array
(
$model
)
;
$this
->
populateRelations
(
$models
,
$this
->
with
);
$models
=
[
$model
]
;
$this
->
findWith
(
$this
->
with
,
$models
);
$model
=
$models
[
0
];
}
return
$model
;
}
/**
* Executes the query and returns the first column of the result.
* @param string $column name of the column to select
* @return array the first column of the query result. An empty array is returned if the query results in nothing.
*/
public
function
column
(
$column
)
{
// TODO add support for indexBy and orderBy
return
$this
->
executeScript
(
'Column'
,
$column
);
}
/**
* Returns the number of records.
* @param string $q the COUNT expression. Defaults to '*'.
* Make sure you properly quote column names.
* @param string $q the COUNT expression. This parameter is ignored by this implementation.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return integer number of records
*/
public
function
count
()
public
function
count
(
$q
=
'*'
,
$db
=
null
)
{
if
(
$this
->
offset
===
null
&&
$this
->
limit
===
null
&&
$this
->
where
===
null
)
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
return
$db
->
executeCommand
(
'LLEN'
,
array
(
$modelClass
::
tableName
()));
if
(
$db
===
null
)
{
$db
=
$modelClass
::
getDb
();
}
return
$db
->
executeCommand
(
'LLEN'
,
[
$modelClass
::
tableName
()]);
}
else
{
return
$this
->
executeScript
(
'Count'
);
return
$this
->
executeScript
(
$db
,
'Count'
);
}
}
/**
* Returns a value indicating whether the query result contains any row of data.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return boolean whether the query result contains any row of data.
*/
public
function
exists
(
$db
=
null
)
{
return
$this
->
one
(
$db
)
!==
null
;
}
/**
* Executes the query and returns the first column of the result.
* @param string $column name of the column to select
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return array the first column of the query result. An empty array is returned if the query results in nothing.
*/
public
function
column
(
$column
,
$db
=
null
)
{
// TODO add support for indexBy and orderBy
return
$this
->
executeScript
(
$db
,
'Column'
,
$column
);
}
/**
* Returns the number of records.
* @param string $column the column to sum up
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return integer number of records
*/
public
function
sum
(
$column
)
public
function
sum
(
$column
,
$db
=
null
)
{
return
$this
->
executeScript
(
'Sum'
,
$column
);
return
$this
->
executeScript
(
$db
,
'Sum'
,
$column
);
}
/**
* Returns the average of the specified column values.
* @param string $column the column name or expression.
* Make sure you properly quote column names in the expression.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return integer the average of the specified column values.
*/
public
function
average
(
$column
)
public
function
average
(
$column
,
$db
=
null
)
{
return
$this
->
executeScript
(
'Average'
,
$column
);
return
$this
->
executeScript
(
$db
,
'Average'
,
$column
);
}
/**
* Returns the minimum of the specified column values.
* @param string $column the column name or expression.
* Make sure you properly quote column names in the expression.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return integer the minimum of the specified column values.
*/
public
function
min
(
$column
)
public
function
min
(
$column
,
$db
=
null
)
{
return
$this
->
executeScript
(
'Min'
,
$column
);
return
$this
->
executeScript
(
$db
,
'Min'
,
$column
);
}
/**
* Returns the maximum of the specified column values.
* @param string $column the column name or expression.
* Make sure you properly quote column names in the expression.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return integer the maximum of the specified column values.
*/
public
function
max
(
$column
)
public
function
max
(
$column
,
$db
=
null
)
{
return
$this
->
executeScript
(
'Max'
,
$column
);
return
$this
->
executeScript
(
$db
,
'Max'
,
$column
);
}
/**
* Returns the query result as a scalar value.
* The value returned will be the first column in the first row of the query results.
* @param string $column name of the column to select
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return string|boolean the value of the first column in the first row of the query result.
* False is returned if the query result is empty.
*/
public
function
scalar
(
$column
)
public
function
scalar
(
$column
,
$db
=
null
)
{
$record
=
$this
->
one
();
return
$record
->
$column
;
$record
=
$this
->
one
(
$db
);
if
(
$record
===
null
)
{
return
false
;
}
else
{
return
$record
->
$column
;
}
}
/**
* Returns a value indicating whether the query result contains any row of data.
* @return boolean whether the query result contains any row of data.
*/
public
function
exists
()
{
return
$this
->
one
()
!==
null
;
}
/**
* Executes a script created by [[LuaScriptBuilder]]
* @param string $type
* @param null $column
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @param string $type the type of the script to generate
* @param string $columnName
* @return array|bool|null|string
*/
protected
function
executeScript
(
$
type
,
$columnName
=
null
)
protected
function
executeScript
(
$
db
,
$type
,
$columnName
=
null
)
{
if
((
$data
=
$this
->
findByPk
(
$type
))
===
false
)
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
/** @var ActiveRecord $modelClass */
$modelClass
=
$this
->
modelClass
;
if
(
$db
===
null
)
{
$db
=
$modelClass
::
getDb
();
}
$method
=
'build'
.
$type
;
$script
=
$db
->
getLuaScriptBuilder
()
->
$method
(
$this
,
$columnName
);
return
$
db
->
executeCommand
(
'EVAL'
,
array
(
$script
,
0
)
);
// find by primary key if possible. This is much faster than scanning all records
if
(
is_array
(
$this
->
where
)
&&
!
isset
(
$this
->
where
[
0
])
&&
$modelClass
::
isPrimaryKey
(
array_keys
(
$this
->
where
)))
{
return
$
this
->
findByPk
(
$db
,
$type
,
$columnName
);
}
return
$data
;
$method
=
'build'
.
$type
;
$script
=
$db
->
getLuaScriptBuilder
()
->
$method
(
$this
,
$columnName
);
return
$db
->
executeCommand
(
'EVAL'
,
[
$script
,
0
]);
}
/**
* Fetch by pk if possible as this is much faster
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @param string $type the type of the script to generate
* @param string $columnName
* @return array|bool|null|string
* @throws \yii\base\NotSupportedException
*/
private
function
findByPk
(
$type
,
$columnName
=
null
)
private
function
findByPk
(
$
db
,
$
type
,
$columnName
=
null
)
{
$modelClass
=
$this
->
modelClass
;
if
(
is_array
(
$this
->
where
)
&&
!
isset
(
$this
->
where
[
0
])
&&
$modelClass
::
isPrimaryKey
(
array_keys
(
$this
->
where
)))
{
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
if
(
count
(
$this
->
where
)
==
1
)
{
$pks
=
(
array
)
reset
(
$this
->
where
);
}
else
{
// TODO support IN for composite PK
return
false
;
if
(
count
(
$this
->
where
)
==
1
)
{
$pks
=
(
array
)
reset
(
$this
->
where
);
}
else
{
foreach
(
$this
->
where
as
$column
=>
$values
)
{
if
(
is_array
(
$values
))
{
// TODO support composite IN for composite PK
throw
new
NotSupportedException
(
'find by composite PK is not yet implemented.'
);
}
}
$pks
=
[
$this
->
where
];
}
$start
=
$this
->
offset
===
null
?
0
:
$this
->
offset
;
$i
=
0
;
$data
=
array
();
foreach
(
$pks
as
$pk
)
{
if
(
++
$i
>
$start
&&
(
$this
->
limit
===
null
||
$i
<=
$start
+
$this
->
limit
))
{
$key
=
$modelClass
::
tableName
()
.
':a:'
.
$modelClass
::
buildKey
(
$pk
);
$result
=
$db
->
executeCommand
(
'HGETALL'
,
array
(
$key
));
if
(
!
empty
(
$result
))
{
$data
[]
=
$result
;
if
(
$type
===
'One'
&&
$this
->
orderBy
===
null
)
{
break
;
}
/** @var ActiveRecord $modelClass */
$modelClass
=
$this
->
modelClass
;
$start
=
$this
->
offset
===
null
?
0
:
$this
->
offset
;
$i
=
0
;
$data
=
[];
foreach
(
$pks
as
$pk
)
{
if
(
++
$i
>
$start
&&
(
$this
->
limit
===
null
||
$i
<=
$start
+
$this
->
limit
))
{
$key
=
$modelClass
::
tableName
()
.
':a:'
.
$modelClass
::
buildKey
(
$pk
);
$result
=
$db
->
executeCommand
(
'HGETALL'
,
[
$key
]);
if
(
!
empty
(
$result
))
{
$data
[]
=
$result
;
if
(
$type
===
'One'
&&
$this
->
orderBy
===
null
)
{
break
;
}
}
}
// TODO support orderBy
switch
(
$type
)
{
case
'All'
:
return
$data
;
case
'One'
:
return
reset
(
$data
);
case
'Column'
:
// TODO support indexBy
$column
=
array
();
foreach
(
$data
as
$dataRow
)
{
$row
=
array
();
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
$row
[
$dataRow
[
$i
++
]]
=
$dataRow
[
$i
++
];
}
$column
[]
=
$row
[
$columnName
];
}
return
$column
;
case
'Count'
:
return
count
(
$data
);
case
'Sum'
:
$sum
=
0
;
foreach
(
$data
as
$dataRow
)
{
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
)
{
$sum
+=
$dataRow
[
$i
];
break
;
}
}
}
// TODO support orderBy
switch
(
$type
)
{
case
'All'
:
return
$data
;
case
'One'
:
return
reset
(
$data
);
case
'Count'
:
return
count
(
$data
);
case
'Column'
:
// TODO support indexBy
$column
=
[];
foreach
(
$data
as
$dataRow
)
{
$row
=
[];
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
$row
[
$dataRow
[
$i
++
]]
=
$dataRow
[
$i
++
];
}
return
$sum
;
case
'Average'
:
$sum
=
0
;
$count
=
0
;
foreach
(
$data
as
$dataRow
)
{
$count
++
;
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
)
{
$sum
+=
$dataRow
[
$i
];
break
;
}
$column
[]
=
$row
[
$columnName
];
}
return
$column
;
case
'Sum'
:
$sum
=
0
;
foreach
(
$data
as
$dataRow
)
{
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
)
{
$sum
+=
$dataRow
[
$i
];
break
;
}
}
return
$sum
/
$count
;
case
'Min'
:
$min
=
null
;
foreach
(
$data
as
$dataRow
)
{
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
&&
(
$min
==
null
||
$dataRow
[
$i
]
<
$min
))
{
$min
=
$dataRow
[
$i
];
break
;
}
}
return
$sum
;
case
'Average'
:
$sum
=
0
;
$count
=
0
;
foreach
(
$data
as
$dataRow
)
{
$count
++
;
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
)
{
$sum
+=
$dataRow
[
$i
];
break
;
}
}
return
$min
;
case
'Max'
:
$max
=
null
;
foreach
(
$data
as
$dataRow
)
{
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
&&
(
$max
==
null
||
$dataRow
[
$i
]
>
$max
)
)
{
$max
=
$dataRow
[
$i
];
break
;
}
}
return
$sum
/
$count
;
case
'Min'
:
$min
=
null
;
foreach
(
$data
as
$dataRow
)
{
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
&&
(
$min
==
null
||
$dataRow
[
$i
]
<
$min
))
{
$min
=
$dataRow
[
$i
]
;
break
;
}
}
return
$max
;
}
}
return
false
;
}
// TODO: refactor. code below here is all duplicated from yii/db/ActiveQuery and yii/db/Query
/**
* Sets the [[asArray]] property.
* @param boolean $value whether to return the query results in terms of arrays instead of Active Records.
* @return ActiveQuery the query object itself
*/
public
function
asArray
(
$value
=
true
)
{
$this
->
asArray
=
$value
;
return
$this
;
}
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return ActiveQuery the query object itself
* @see addOrderBy()
*/
public
function
orderBy
(
$columns
)
{
$this
->
orderBy
=
$this
->
normalizeOrderBy
(
$columns
);
return
$this
;
}
/**
* Adds additional ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return ActiveQuery the query object itself
* @see orderBy()
*/
public
function
addOrderBy
(
$columns
)
{
$columns
=
$this
->
normalizeOrderBy
(
$columns
);
if
(
$this
->
orderBy
===
null
)
{
$this
->
orderBy
=
$columns
;
}
else
{
$this
->
orderBy
=
array_merge
(
$this
->
orderBy
,
$columns
);
}
return
$this
;
}
protected
function
normalizeOrderBy
(
$columns
)
{
throw
new
NotSupportedException
(
'orderBy is currently not supported'
);
if
(
is_array
(
$columns
))
{
return
$columns
;
}
else
{
$columns
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$columns
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
$result
=
array
();
foreach
(
$columns
as
$column
)
{
if
(
preg_match
(
'/^(.*?)\s+(asc|desc)$/i'
,
$column
,
$matches
))
{
$result
[
$matches
[
1
]]
=
strcasecmp
(
$matches
[
2
],
'desc'
)
?
self
::
SORT_ASC
:
self
::
SORT_DESC
;
}
else
{
$result
[
$column
]
=
self
::
SORT_ASC
;
}
}
return
$result
;
}
}
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit
* @return ActiveQuery the query object itself
*/
public
function
limit
(
$limit
)
{
$this
->
limit
=
$limit
;
return
$this
;
}
/**
* Sets the OFFSET part of the query.
* @param integer $offset the offset
* @return ActiveQuery the query object itself
*/
public
function
offset
(
$offset
)
{
$this
->
offset
=
$offset
;
return
$this
;
}
/**
* Specifies the relations with which this query should be performed.
*
* The parameters to this method can be either one or multiple strings, or a single array
* of relation names and the optional callbacks to customize the relations.
*
* The followings are some usage examples:
*
* ~~~
* // find customers together with their orders and country
* Customer::find()->with('orders', 'country')->all();
* // find customers together with their country and orders of status 1
* Customer::find()->with(array(
* 'orders' => function($query) {
* $query->andWhere('status = 1');
* },
* 'country',
* ))->all();
* ~~~
*
* @return ActiveQuery the query object itself
*/
public
function
with
()
{
$this
->
with
=
func_get_args
();
if
(
isset
(
$this
->
with
[
0
])
&&
is_array
(
$this
->
with
[
0
]))
{
// the parameter is given as an array
$this
->
with
=
$this
->
with
[
0
];
}
return
$this
;
}
/**
* Sets the [[indexBy]] property.
* @param string|callable $column the name of the column by which the query results should be indexed by.
* This can also be a callable (e.g. anonymous function) that returns the index value based on the given
* row or model data. The signature of the callable should be:
*
* ~~~
* // $model is an AR instance when `asArray` is false,
* // or an array of column values when `asArray` is true.
* function ($model)
* {
* // return the index value corresponding to $model
* }
* ~~~
*
* @return ActiveQuery the query object itself
*/
public
function
indexBy
(
$column
)
{
$this
->
indexBy
=
$column
;
return
$this
;
}
/**
* Sets the WHERE part of the query.
*
* The method requires a $condition parameter, and optionally a $params parameter
* specifying the values to be bound to the query.
*
* The $condition parameter should be either a string (e.g. 'id=1') or an array.
* If the latter, it must be in one of the following two formats:
*
* - hash format: `array('column1' => value1, 'column2' => value2, ...)`
* - operator format: `array(operator, operand1, operand2, ...)`
*
* A condition in hash format represents the following SQL expression in general:
* `column1=value1 AND column2=value2 AND ...`. In case when a value is an array,
* an `IN` expression will be generated. And if a value is null, `IS NULL` will be used
* in the generated expression. Below are some examples:
*
* - `array('type' => 1, 'status' => 2)` generates `(type = 1) AND (status = 2)`.
* - `array('id' => array(1, 2, 3), 'status' => 2)` generates `(id IN (1, 2, 3)) AND (status = 2)`.
* - `array('status' => null) generates `status IS NULL`.
*
* A condition in operator format generates the SQL expression according to the specified operator, which
* can be one of the followings:
*
* - `and`: the operands should be concatenated together using `AND`. For example,
* `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array,
* it will be converted into a string using the rules described here. For example,
* `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`.
* The method will NOT do any quoting or escaping.
*
* - `or`: similar to the `and` operator except that the operands are concatenated using `OR`.
*
* - `between`: operand 1 should be the column name, and operand 2 and 3 should be the
* starting and ending values of the range that the column is in.
* For example, `array('between', 'id', 1, 10)` will generate `id BETWEEN 1 AND 10`.
*
* - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN`
* in the generated condition.
*
* - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing
* the range of the values that the column or DB expression should be in. For example,
* `array('in', 'id', array(1, 2, 3))` will generate `id IN (1, 2, 3)`.
* The method will properly quote the column name and escape values in the range.
*
* - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition.
*
* - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing
* the values that the column or DB expression should be like.
* For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`.
* When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated
* using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate
* `name LIKE '%test%' AND name LIKE '%sample%'`.
* The method will properly quote the column name and escape values in the range.
*
* - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE`
* predicates when operand 2 is an array.
*
* - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE`
* in the generated condition.
*
* - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate
* the `NOT LIKE` predicates.
*
* @param string|array $condition the conditions that should be put in the WHERE part.
* @return ActiveQuery the query object itself
* @see andWhere()
* @see orWhere()
*/
public
function
where
(
$condition
)
{
$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 'AND' operator.
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return ActiveQuery the query object itself
* @see where()
* @see orWhere()
*/
public
function
andWhere
(
$condition
)
{
if
(
$this
->
where
===
null
)
{
$this
->
where
=
$condition
;
}
else
{
$this
->
where
=
array
(
'and'
,
$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 string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return ActiveQuery the query object itself
* @see where()
* @see andWhere()
*/
public
function
orWhere
(
$condition
)
{
if
(
$this
->
where
===
null
)
{
$this
->
where
=
$condition
;
}
else
{
$this
->
where
=
array
(
'or'
,
$this
->
where
,
$condition
);
}
return
$this
;
}
private
function
createModels
(
$rows
)
{
$models
=
array
();
if
(
$this
->
asArray
)
{
if
(
$this
->
indexBy
===
null
)
{
return
$rows
;
}
foreach
(
$rows
as
$row
)
{
if
(
is_string
(
$this
->
indexBy
))
{
$key
=
$row
[
$this
->
indexBy
];
}
else
{
$key
=
call_user_func
(
$this
->
indexBy
,
$row
);
}
$models
[
$key
]
=
$row
;
}
}
else
{
/** @var $class ActiveRecord */
$class
=
$this
->
modelClass
;
if
(
$this
->
indexBy
===
null
)
{
foreach
(
$rows
as
$row
)
{
$models
[]
=
$class
::
create
(
$row
);
}
}
else
{
foreach
(
$rows
as
$row
)
{
$model
=
$class
::
create
(
$row
);
if
(
is_string
(
$this
->
indexBy
))
{
$key
=
$model
->
{
$this
->
indexBy
};
}
else
{
$key
=
call_user_func
(
$this
->
indexBy
,
$model
);
return
$min
;
case
'Max'
:
$max
=
null
;
foreach
(
$data
as
$dataRow
)
{
$c
=
count
(
$dataRow
);
for
(
$i
=
0
;
$i
<
$c
;
)
{
if
(
$dataRow
[
$i
++
]
==
$columnName
&&
(
$max
==
null
||
$dataRow
[
$i
]
>
$max
))
{
$max
=
$dataRow
[
$i
];
break
;
}
}
$models
[
$key
]
=
$model
;
}
}
}
return
$models
;
}
private
function
populateRelations
(
&
$models
,
$with
)
{
$primaryModel
=
new
$this
->
modelClass
;
$relations
=
$this
->
normalizeRelations
(
$primaryModel
,
$with
);
foreach
(
$relations
as
$name
=>
$relation
)
{
if
(
$relation
->
asArray
===
null
)
{
// inherit asArray from primary query
$relation
->
asArray
=
$this
->
asArray
;
}
$relation
->
findWith
(
$name
,
$models
);
}
}
/**
* @param ActiveRecord $model
* @param array $with
* @return ActiveRelation[]
*/
private
function
normalizeRelations
(
$model
,
$with
)
{
$relations
=
array
();
foreach
(
$with
as
$name
=>
$callback
)
{
if
(
is_integer
(
$name
))
{
$name
=
$callback
;
$callback
=
null
;
}
if
((
$pos
=
strpos
(
$name
,
'.'
))
!==
false
)
{
// with sub-relations
$childName
=
substr
(
$name
,
$pos
+
1
);
$name
=
substr
(
$name
,
0
,
$pos
);
}
else
{
$childName
=
null
;
}
$t
=
strtolower
(
$name
);
if
(
!
isset
(
$relations
[
$t
]))
{
$relation
=
$model
->
getRelation
(
$name
);
$relation
->
primaryModel
=
null
;
$relations
[
$t
]
=
$relation
;
}
else
{
$relation
=
$relations
[
$t
];
}
if
(
isset
(
$childName
))
{
$relation
->
with
[
$childName
]
=
$callback
;
}
elseif
(
$callback
!==
null
)
{
call_user_func
(
$callback
,
$relation
);
}
return
$max
;
}
return
$relations
;
throw
new
InvalidParamException
(
'Unknown fetch type: '
.
$type
)
;
}
}
framework/yii/redis/ActiveRecord.php
View file @
8542448f
...
...
@@ -23,7 +23,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
/**
* @var array cache for TableSchema instances
*/
private
static
$_tables
=
array
()
;
private
static
$_tables
=
[]
;
/**
* Returns the database connection used by this AR class.
...
...
@@ -33,23 +33,111 @@ class ActiveRecord extends \yii\db\ActiveRecord
*/
public
static
function
getDb
()
{
return
\Yii
::
$app
->
redis
;
return
\Yii
::
$app
->
getComponent
(
'redis'
)
;
}
/**
* @inheritdoc
*/
public
static
function
findBySql
(
$sql
,
$params
=
array
()
)
public
static
function
findBySql
(
$sql
,
$params
=
[]
)
{
throw
new
NotSupportedException
(
'findBySql() is not supported by redis ActiveRecord'
);
}
/**
* @inheritDoc
*/
public
static
function
createQuery
()
{
return
new
ActiveQuery
([
'modelClass'
=>
get_called_class
()]);
}
/**
* @inheritDoc
*/
protected
function
createActiveRelation
(
$config
=
[])
{
return
new
ActiveRelation
(
$config
);
}
/**
* Declares the name of the database table associated with this AR class.
* @return string the table name
*/
public
static
function
tableName
()
{
return
static
::
getTableSchema
()
->
name
;
}
/**
* This method is ment to be overridden in redis ActiveRecord subclasses to return a [[RecordSchema]] instance.
* @return RecordSchema
* @throws \yii\base\InvalidConfigException
*/
public
static
function
getRecordSchema
()
{
throw
new
InvalidConfigException
(
__CLASS__
.
'::getRecordSchema() needs to be overridden in subclasses and return a RecordSchema.'
);
}
/**
* Returns the schema information of the DB table associated with this AR class.
* @return TableSchema the schema information of the DB table associated with this AR class.
*/
public
static
function
getTableSchema
()
{
$class
=
get_called_class
();
if
(
isset
(
self
::
$_tables
[
$class
]))
{
return
self
::
$_tables
[
$class
];
}
return
self
::
$_tables
[
$class
]
=
static
::
getRecordSchema
();
}
/**
* @inheritDocs
*/
public
function
insert
(
$runValidation
=
true
,
$attributes
=
null
)
{
if
(
$runValidation
&&
!
$this
->
validate
(
$attributes
))
{
return
false
;
}
if
(
$this
->
beforeSave
(
true
))
{
$db
=
static
::
getDb
();
$values
=
$this
->
getDirtyAttributes
(
$attributes
);
$pk
=
[];
// if ($values === []) {
foreach
(
$this
->
primaryKey
()
as
$key
)
{
$pk
[
$key
]
=
$values
[
$key
]
=
$this
->
getAttribute
(
$key
);
if
(
$pk
[
$key
]
===
null
)
{
$pk
[
$key
]
=
$values
[
$key
]
=
$db
->
executeCommand
(
'INCR'
,
[
static
::
tableName
()
.
':s:'
.
$key
]);
$this
->
setAttribute
(
$key
,
$values
[
$key
]);
}
}
// }
// save pk in a findall pool
$db
->
executeCommand
(
'RPUSH'
,
[
static
::
tableName
(),
static
::
buildKey
(
$pk
)]);
$key
=
static
::
tableName
()
.
':a:'
.
static
::
buildKey
(
$pk
);
// save attributes
$args
=
[
$key
];
foreach
(
$values
as
$attribute
=>
$value
)
{
$args
[]
=
$attribute
;
$args
[]
=
$value
;
}
$db
->
executeCommand
(
'HMSET'
,
$args
);
$this
->
setOldAttributes
(
$values
);
$this
->
afterSave
(
true
);
return
true
;
}
return
false
;
}
/**
* Updates the whole table using the provided attribute values and conditions.
* For example, to change the status to be 1 for all customers whose status is 2:
*
* ~~~
* Customer::updateAll(
array('status' => 1), array('id' => 2)
);
* Customer::updateAll(
['status' => 1], ['id' => 2]
);
* ~~~
*
* @param array $attributes attribute values (name-value pairs) to be saved into the table
...
...
@@ -58,7 +146,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
* @param array $params this parameter is ignored in redis implementation.
* @return integer the number of rows updated
*/
public
static
function
updateAll
(
$attributes
,
$condition
=
null
,
$params
=
array
()
)
public
static
function
updateAll
(
$attributes
,
$condition
=
null
,
$params
=
[]
)
{
if
(
empty
(
$attributes
))
{
return
0
;
...
...
@@ -70,7 +158,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
$pk
=
static
::
buildKey
(
$pk
);
$key
=
static
::
tableName
()
.
':a:'
.
$pk
;
// save attributes
$args
=
array
(
$key
)
;
$args
=
[
$key
]
;
foreach
(
$attributes
as
$attribute
=>
$value
)
{
if
(
isset
(
$newPk
[
$attribute
]))
{
$newPk
[
$attribute
]
=
$value
;
...
...
@@ -84,9 +172,9 @@ class ActiveRecord extends \yii\db\ActiveRecord
if
(
$newPk
!=
$pk
)
{
$db
->
executeCommand
(
'MULTI'
);
$db
->
executeCommand
(
'HMSET'
,
$args
);
$db
->
executeCommand
(
'LINSERT'
,
array
(
static
::
tableName
(),
'AFTER'
,
$pk
,
$newPk
)
);
$db
->
executeCommand
(
'LREM'
,
array
(
static
::
tableName
(),
0
,
$pk
)
);
$db
->
executeCommand
(
'RENAME'
,
array
(
$key
,
$newKey
)
);
$db
->
executeCommand
(
'LINSERT'
,
[
static
::
tableName
(),
'AFTER'
,
$pk
,
$newPk
]
);
$db
->
executeCommand
(
'LREM'
,
[
static
::
tableName
(),
0
,
$pk
]
);
$db
->
executeCommand
(
'RENAME'
,
[
$key
,
$newKey
]
);
$db
->
executeCommand
(
'EXEC'
);
}
else
{
$db
->
executeCommand
(
'HMSET'
,
$args
);
...
...
@@ -101,7 +189,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
* For example, to increment all customers' age by 1,
*
* ~~~
* Customer::updateAllCounters(
array('age' => 1)
);
* Customer::updateAllCounters(
['age' => 1]
);
* ~~~
*
* @param array $counters the counters to be updated (attribute name => increment value).
...
...
@@ -111,7 +199,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
* @param array $params this parameter is ignored in redis implementation.
* @return integer the number of rows updated
*/
public
static
function
updateAllCounters
(
$counters
,
$condition
=
null
,
$params
=
array
()
)
public
static
function
updateAllCounters
(
$counters
,
$condition
=
null
,
$params
=
[]
)
{
if
(
empty
(
$counters
))
{
return
0
;
...
...
@@ -121,7 +209,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
foreach
(
static
::
fetchPks
(
$condition
)
as
$pk
)
{
$key
=
static
::
tableName
()
.
':a:'
.
static
::
buildKey
(
$pk
);
foreach
(
$counters
as
$attribute
=>
$value
)
{
$db
->
executeCommand
(
'HINCRBY'
,
array
(
$key
,
$attribute
,
$value
)
);
$db
->
executeCommand
(
'HINCRBY'
,
[
$key
,
$attribute
,
$value
]
);
}
$n
++
;
}
...
...
@@ -135,7 +223,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
* For example, to delete all customers whose status is 3:
*
* ~~~
* Customer::deleteAll(
'status = 3'
);
* Customer::deleteAll(
['status' => 3]
);
* ~~~
*
* @param array $condition the conditions that will be put in the WHERE part of the DELETE SQL.
...
...
@@ -143,15 +231,15 @@ class ActiveRecord extends \yii\db\ActiveRecord
* @param array $params this parameter is ignored in redis implementation.
* @return integer the number of rows deleted
*/
public
static
function
deleteAll
(
$condition
=
null
,
$params
=
array
()
)
public
static
function
deleteAll
(
$condition
=
null
,
$params
=
[]
)
{
$db
=
static
::
getDb
();
$attributeKeys
=
array
()
;
$attributeKeys
=
[]
;
$pks
=
static
::
fetchPks
(
$condition
);
$db
->
executeCommand
(
'MULTI'
);
foreach
(
$pks
as
$pk
)
{
$pk
=
static
::
buildKey
(
$pk
);
$db
->
executeCommand
(
'LREM'
,
array
(
static
::
tableName
(),
0
,
$pk
)
);
$db
->
executeCommand
(
'LREM'
,
[
static
::
tableName
(),
0
,
$pk
]
);
$attributeKeys
[]
=
static
::
tableName
()
.
':a:'
.
$pk
;
}
if
(
empty
(
$attributeKeys
))
{
...
...
@@ -170,9 +258,9 @@ class ActiveRecord extends \yii\db\ActiveRecord
$records
=
$query
->
asArray
()
->
all
();
// TODO limit fetched columns to pk
$primaryKey
=
static
::
primaryKey
();
$pks
=
array
()
;
$pks
=
[]
;
foreach
(
$records
as
$record
)
{
$pk
=
array
()
;
$pk
=
[]
;
foreach
(
$primaryKey
as
$key
)
{
$pk
[
$key
]
=
$record
[
$key
];
}
...
...
@@ -197,6 +285,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
if
(
count
(
$key
)
==
1
)
{
return
self
::
buildKey
(
reset
(
$key
));
}
ksort
(
$key
);
// ensure order is always the same
$isNumeric
=
true
;
foreach
(
$key
as
$value
)
{
if
(
!
is_numeric
(
$value
))
{
...
...
@@ -211,171 +300,6 @@ class ActiveRecord extends \yii\db\ActiveRecord
}
/**
* Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query.
* You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.)
* @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/
public
static
function
createQuery
()
{
return
new
ActiveQuery
(
array
(
'modelClass'
=>
get_called_class
(),
));
}
/**
* Declares the name of the database table associated with this AR class.
* @return string the table name
*/
public
static
function
tableName
()
{
return
static
::
getTableSchema
()
->
name
;
}
/**
* This method is ment to be overridden in redis ActiveRecord subclasses to return a [[RecordSchema]] instance.
* @return RecordSchema
* @throws \yii\base\InvalidConfigException
*/
public
static
function
getRecordSchema
()
{
throw
new
InvalidConfigException
(
__CLASS__
.
'::getRecordSchema() needs to be overridden in subclasses and return a RecordSchema.'
);
}
/**
* Returns the schema information of the DB table associated with this AR class.
* @return TableSchema the schema information of the DB table associated with this AR class.
*/
public
static
function
getTableSchema
()
{
$class
=
get_called_class
();
if
(
isset
(
self
::
$_tables
[
$class
]))
{
return
self
::
$_tables
[
$class
];
}
return
self
::
$_tables
[
$class
]
=
static
::
getRecordSchema
();
}
/**
* Declares a `has-one` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance
* through which the related record can be queried and retrieved back.
*
* A `has-one` relation means that there is at most one related record matching
* the criteria set by this relation, e.g., a customer has one country.
*
* For example, to declare the `country` relation for `Customer` class, we can write
* the following code in the `Customer` class:
*
* ~~~
* public function getCountry()
* {
* return $this->hasOne('Country', array('id' => 'country_id'));
* }
* ~~~
*
* Note that in the above, the 'id' key in the `$link` parameter refers to an attribute name
* in the related class `Country`, while the 'country_id' value refers to an attribute name
* in the current AR class.
*
* Call methods declared in [[ActiveRelation]] to further customize the relation.
*
* @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to
* the columns in the table associated with the `$class` model, while the values of the
* array refer to the corresponding columns in the table associated with this AR class.
* @return ActiveRelation the relation object.
*/
public
function
hasOne
(
$class
,
$link
)
{
return
new
ActiveRelation
(
array
(
'modelClass'
=>
$this
->
getNamespacedClass
(
$class
),
'primaryModel'
=>
$this
,
'link'
=>
$link
,
'multiple'
=>
false
,
));
}
/**
* Declares a `has-many` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance
* through which the related record can be queried and retrieved back.
*
* A `has-many` relation means that there are multiple related records matching
* the criteria set by this relation, e.g., a customer has many orders.
*
* For example, to declare the `orders` relation for `Customer` class, we can write
* the following code in the `Customer` class:
*
* ~~~
* public function getOrders()
* {
* return $this->hasMany('Order', array('customer_id' => 'id'));
* }
* ~~~
*
* Note that in the above, the 'customer_id' key in the `$link` parameter refers to
* an attribute name in the related class `Order`, while the 'id' value refers to
* an attribute name in the current AR class.
*
* @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to
* the columns in the table associated with the `$class` model, while the values of the
* array refer to the corresponding columns in the table associated with this AR class.
* @return ActiveRelation the relation object.
*/
public
function
hasMany
(
$class
,
$link
)
{
return
new
ActiveRelation
(
array
(
'modelClass'
=>
$this
->
getNamespacedClass
(
$class
),
'primaryModel'
=>
$this
,
'link'
=>
$link
,
'multiple'
=>
true
,
));
}
/**
* @inheritDocs
*/
public
function
insert
(
$runValidation
=
true
,
$attributes
=
null
)
{
if
(
$runValidation
&&
!
$this
->
validate
(
$attributes
))
{
return
false
;
}
if
(
$this
->
beforeSave
(
true
))
{
$db
=
static
::
getDb
();
$values
=
$this
->
getDirtyAttributes
(
$attributes
);
$pk
=
array
();
// if ($values === array()) {
foreach
(
$this
->
primaryKey
()
as
$key
)
{
$pk
[
$key
]
=
$values
[
$key
]
=
$this
->
getAttribute
(
$key
);
if
(
$pk
[
$key
]
===
null
)
{
$pk
[
$key
]
=
$values
[
$key
]
=
$db
->
executeCommand
(
'INCR'
,
array
(
static
::
tableName
()
.
':s:'
.
$key
));
$this
->
setAttribute
(
$key
,
$values
[
$key
]);
}
}
// }
// save pk in a findall pool
$db
->
executeCommand
(
'RPUSH'
,
array
(
static
::
tableName
(),
static
::
buildKey
(
$pk
)));
$key
=
static
::
tableName
()
.
':a:'
.
static
::
buildKey
(
$pk
);
// save attributes
$args
=
array
(
$key
);
foreach
(
$values
as
$attribute
=>
$value
)
{
$args
[]
=
$attribute
;
$args
[]
=
$value
;
}
$db
->
executeCommand
(
'HMSET'
,
$args
);
$this
->
setOldAttributes
(
$values
);
$this
->
afterSave
(
true
);
return
true
;
}
return
false
;
}
/**
* Returns a value indicating whether the specified operation is transactional in the current [[scenario]].
* This method will always return false as transactional operations are not supported by redis.
* @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]].
...
...
framework/yii/redis/ActiveRelation.php
View file @
8542448f
...
...
@@ -7,9 +7,8 @@
namespace
yii\redis
;
use
yii\base\InvalidConfigException
;
// TODO this class is nearly completely duplicated from yii\db\ActiveRelation
use
yii\db\ActiveRelationInterface
;
use
yii\db\ActiveRelationTrait
;
/**
* ActiveRelation represents a relation between two Active Record classes.
...
...
@@ -26,76 +25,29 @@ use yii\base\InvalidConfigException;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class
ActiveRelation
extends
ActiveQuery
class
ActiveRelation
extends
ActiveQuery
implements
ActiveRelationInterface
{
/**
* @var boolean whether this relation should populate all query results into AR instances.
* If false, only the first row of the results will be retrieved.
*/
public
$multiple
;
/**
* @var ActiveRecord the primary model that this relation is associated with.
* This is used only in lazy loading with dynamic query options.
*/
public
$primaryModel
;
/**
* @var array the columns of the primary and foreign tables that establish the relation.
* The array keys must be columns of the table for this relation, and the array values
* must be the corresponding columns from the primary table.
* Do not prefix or quote the column names as this will be done automatically by Yii.
*/
public
$link
;
/**
* @var array|ActiveRelation the query associated with the pivot table. Please call [[via()]]
* or [[viaTable()]] to set this property instead of directly setting it.
*/
public
$via
;
/**
* Clones internal objects.
*/
public
function
__clone
()
{
if
(
is_object
(
$this
->
via
))
{
// make a clone of "via" object so that the same query object can be reused multiple times
$this
->
via
=
clone
$this
->
via
;
}
}
use
ActiveRelationTrait
;
/**
* Specifies the relation associated with the pivot table.
* @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]].
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
* @return ActiveRelation the relation object itself.
* Executes a script created by [[LuaScriptBuilder]]
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @param string $type the type of the script to generate
* @param null $column
* @return array|bool|null|string
*/
public
function
via
(
$relationName
,
$callable
=
null
)
{
$relation
=
$this
->
primaryModel
->
getRelation
(
$relationName
);
$this
->
via
=
array
(
$relationName
,
$relation
);
if
(
$callable
!==
null
)
{
call_user_func
(
$callable
,
$relation
);
}
return
$this
;
}
/**
* Creates a DB command that can be used to execute this query.
* @param Connection $db the DB connection used to create the DB command.
* If null, the DB connection returned by [[modelClass]] will be used.
* @return Command the created DB command instance.
*/
protected
function
executeScript
(
$type
,
$column
=
null
)
protected
function
executeScript
(
$db
,
$type
,
$column
=
null
)
{
if
(
$this
->
primaryModel
!==
null
)
{
// lazy loading
if
(
$this
->
via
instanceof
self
)
{
// via pivot table
$viaModels
=
$this
->
via
->
findPivotRows
(
array
(
$this
->
primaryModel
)
);
$viaModels
=
$this
->
via
->
findPivotRows
(
[
$this
->
primaryModel
]
);
$this
->
filterByModels
(
$viaModels
);
}
elseif
(
is_array
(
$this
->
via
))
{
// via relation
/** @var
$viaQuery ActiveRelation
*/
/** @var
ActiveRelation $viaQuery
*/
list
(
$viaName
,
$viaQuery
)
=
$this
->
via
;
if
(
$viaQuery
->
multiple
)
{
$viaModels
=
$viaQuery
->
all
();
...
...
@@ -103,187 +55,13 @@ class ActiveRelation extends ActiveQuery
}
else
{
$model
=
$viaQuery
->
one
();
$this
->
primaryModel
->
populateRelation
(
$viaName
,
$model
);
$viaModels
=
$model
===
null
?
array
()
:
array
(
$model
)
;
$viaModels
=
$model
===
null
?
[]
:
[
$model
]
;
}
$this
->
filterByModels
(
$viaModels
);
}
else
{
$this
->
filterByModels
(
array
(
$this
->
primaryModel
));
}
}
return
parent
::
executeScript
(
$type
,
$column
);
}
/**
* Finds the related records and populates them into the primary models.
* This method is internally used by [[ActiveQuery]]. Do not call it directly.
* @param string $name the relation name
* @param array $primaryModels primary models
* @return array the related models
* @throws InvalidConfigException
*/
public
function
findWith
(
$name
,
&
$primaryModels
)
{
if
(
!
is_array
(
$this
->
link
))
{
throw
new
InvalidConfigException
(
'Invalid link: it must be an array of key-value pairs.'
);
}
if
(
$this
->
via
instanceof
self
)
{
// via pivot table
/** @var $viaQuery ActiveRelation */
$viaQuery
=
$this
->
via
;
$viaModels
=
$viaQuery
->
findPivotRows
(
$primaryModels
);
$this
->
filterByModels
(
$viaModels
);
}
elseif
(
is_array
(
$this
->
via
))
{
// via relation
/** @var $viaQuery ActiveRelation */
list
(
$viaName
,
$viaQuery
)
=
$this
->
via
;
$viaQuery
->
primaryModel
=
null
;
$viaModels
=
$viaQuery
->
findWith
(
$viaName
,
$primaryModels
);
$this
->
filterByModels
(
$viaModels
);
}
else
{
$this
->
filterByModels
(
$primaryModels
);
}
if
(
count
(
$primaryModels
)
===
1
&&
!
$this
->
multiple
)
{
$model
=
$this
->
one
();
foreach
(
$primaryModels
as
$i
=>
$primaryModel
)
{
if
(
$primaryModel
instanceof
ActiveRecord
)
{
$primaryModel
->
populateRelation
(
$name
,
$model
);
}
else
{
$primaryModels
[
$i
][
$name
]
=
$model
;
}
}
return
array
(
$model
);
}
else
{
$models
=
$this
->
all
();
if
(
isset
(
$viaModels
,
$viaQuery
))
{
$buckets
=
$this
->
buildBuckets
(
$models
,
$this
->
link
,
$viaModels
,
$viaQuery
->
link
);
}
else
{
$buckets
=
$this
->
buildBuckets
(
$models
,
$this
->
link
);
}
$link
=
array_values
(
isset
(
$viaQuery
)
?
$viaQuery
->
link
:
$this
->
link
);
foreach
(
$primaryModels
as
$i
=>
$primaryModel
)
{
$key
=
$this
->
getModelKey
(
$primaryModel
,
$link
);
$value
=
isset
(
$buckets
[
$key
])
?
$buckets
[
$key
]
:
(
$this
->
multiple
?
array
()
:
null
);
if
(
$primaryModel
instanceof
ActiveRecord
)
{
$primaryModel
->
populateRelation
(
$name
,
$value
);
}
else
{
$primaryModels
[
$i
][
$name
]
=
$value
;
}
}
return
$models
;
}
}
/**
* @param array $models
* @param array $link
* @param array $viaModels
* @param array $viaLink
* @return array
*/
private
function
buildBuckets
(
$models
,
$link
,
$viaModels
=
null
,
$viaLink
=
null
)
{
$buckets
=
array
();
$linkKeys
=
array_keys
(
$link
);
foreach
(
$models
as
$i
=>
$model
)
{
$key
=
$this
->
getModelKey
(
$model
,
$linkKeys
);
if
(
$this
->
indexBy
!==
null
)
{
$buckets
[
$key
][
$i
]
=
$model
;
}
else
{
$buckets
[
$key
][]
=
$model
;
}
}
if
(
$viaModels
!==
null
)
{
$viaBuckets
=
array
();
$viaLinkKeys
=
array_keys
(
$viaLink
);
$linkValues
=
array_values
(
$link
);
foreach
(
$viaModels
as
$viaModel
)
{
$key1
=
$this
->
getModelKey
(
$viaModel
,
$viaLinkKeys
);
$key2
=
$this
->
getModelKey
(
$viaModel
,
$linkValues
);
if
(
isset
(
$buckets
[
$key2
]))
{
foreach
(
$buckets
[
$key2
]
as
$i
=>
$bucket
)
{
if
(
$this
->
indexBy
!==
null
)
{
$viaBuckets
[
$key1
][
$i
]
=
$bucket
;
}
else
{
$viaBuckets
[
$key1
][]
=
$bucket
;
}
}
}
}
$buckets
=
$viaBuckets
;
}
if
(
!
$this
->
multiple
)
{
foreach
(
$buckets
as
$i
=>
$bucket
)
{
$buckets
[
$i
]
=
reset
(
$bucket
);
$this
->
filterByModels
([
$this
->
primaryModel
]);
}
}
return
$buckets
;
}
/**
* @param ActiveRecord|array $model
* @param array $attributes
* @return string
*/
private
function
getModelKey
(
$model
,
$attributes
)
{
if
(
count
(
$attributes
)
>
1
)
{
$key
=
array
();
foreach
(
$attributes
as
$attribute
)
{
$key
[]
=
$model
[
$attribute
];
}
return
serialize
(
$key
);
}
else
{
$attribute
=
reset
(
$attributes
);
return
$model
[
$attribute
];
}
}
/**
* @param array $models
*/
private
function
filterByModels
(
$models
)
{
$attributes
=
array_keys
(
$this
->
link
);
$values
=
array
();
if
(
count
(
$attributes
)
===
1
)
{
// single key
$attribute
=
reset
(
$this
->
link
);
foreach
(
$models
as
$model
)
{
if
((
$value
=
$model
[
$attribute
])
!==
null
)
{
$values
[]
=
$value
;
}
}
}
else
{
// composite keys
foreach
(
$models
as
$model
)
{
$v
=
array
();
foreach
(
$this
->
link
as
$attribute
=>
$link
)
{
$v
[
$attribute
]
=
$model
[
$link
];
}
$values
[]
=
$v
;
}
}
$this
->
andWhere
(
array
(
'in'
,
$attributes
,
array_unique
(
$values
,
SORT_REGULAR
)));
}
/**
* @param ActiveRecord[] $primaryModels
* @return array
*/
private
function
findPivotRows
(
$primaryModels
)
{
if
(
empty
(
$primaryModels
))
{
return
array
();
}
$this
->
filterByModels
(
$primaryModels
);
/** @var $primaryModel ActiveRecord */
$primaryModel
=
reset
(
$primaryModels
);
$db
=
$primaryModel
->
getDb
();
// TODO use different db in db overlapping relations
return
$this
->
all
();
return
parent
::
executeScript
(
$db
,
$type
,
$column
);
}
}
framework/yii/redis/LuaScriptBuilder.php
View file @
8542448f
...
...
@@ -129,7 +129,7 @@ class LuaScriptBuilder extends \yii\base\Object
*/
private
function
build
(
$query
,
$buildResult
,
$return
)
{
$columns
=
array
()
;
$columns
=
[]
;
if
(
$query
->
where
!==
null
)
{
$condition
=
$this
->
buildCondition
(
$query
->
where
,
$columns
);
}
else
{
...
...
@@ -206,7 +206,7 @@ EOF;
*/
public
function
buildCondition
(
$condition
,
&
$columns
)
{
static
$builders
=
array
(
static
$builders
=
[
'and'
=>
'buildAndCondition'
,
'or'
=>
'buildAndCondition'
,
'between'
=>
'buildBetweenCondition'
,
...
...
@@ -217,7 +217,7 @@ EOF;
'not like'
=>
'buildLikeCondition'
,
'or like'
=>
'buildLikeCondition'
,
'or not like'
=>
'buildLikeCondition'
,
)
;
]
;
if
(
!
is_array
(
$condition
))
{
throw
new
NotSupportedException
(
'Where must be an array.'
);
...
...
@@ -238,10 +238,10 @@ EOF;
private
function
buildHashCondition
(
$condition
,
&
$columns
)
{
$parts
=
array
()
;
$parts
=
[]
;
foreach
(
$condition
as
$column
=>
$value
)
{
if
(
is_array
(
$value
))
{
// IN condition
$parts
[]
=
$this
->
buildInCondition
(
'in'
,
array
(
$column
,
$value
)
,
$columns
);
$parts
[]
=
$this
->
buildInCondition
(
'in'
,
[
$column
,
$value
]
,
$columns
);
}
else
{
$column
=
$this
->
addColumn
(
$column
,
$columns
);
if
(
$value
===
null
)
{
...
...
@@ -259,7 +259,7 @@ EOF;
private
function
buildAndCondition
(
$operator
,
$operands
,
&
$columns
)
{
$parts
=
array
()
;
$parts
=
[]
;
foreach
(
$operands
as
$operand
)
{
if
(
is_array
(
$operand
))
{
$operand
=
$this
->
buildCondition
(
$operand
,
$columns
);
...
...
@@ -299,7 +299,7 @@ EOF;
$values
=
(
array
)
$values
;
if
(
empty
(
$values
)
||
$column
===
array
()
)
{
if
(
empty
(
$values
)
||
$column
===
[]
)
{
return
$operator
===
'in'
?
'false'
:
'true'
;
}
...
...
@@ -309,7 +309,7 @@ EOF;
$column
=
reset
(
$column
);
}
$columnAlias
=
$this
->
addColumn
(
$column
,
$columns
);
$parts
=
array
()
;
$parts
=
[]
;
foreach
(
$values
as
$i
=>
$value
)
{
if
(
is_array
(
$value
))
{
$value
=
isset
(
$value
[
$column
])
?
$value
[
$column
]
:
null
;
...
...
@@ -329,9 +329,9 @@ EOF;
protected
function
buildCompositeInCondition
(
$operator
,
$inColumns
,
$values
,
&
$columns
)
{
$vss
=
array
()
;
$vss
=
[]
;
foreach
(
$values
as
$value
)
{
$vs
=
array
()
;
$vs
=
[]
;
foreach
(
$inColumns
as
$column
)
{
$column
=
$this
->
addColumn
(
$column
,
$columns
);
if
(
isset
(
$value
[
$column
]))
{
...
...
@@ -370,7 +370,7 @@ EOF;
$column
=
$this
->
addColumn
(
$column
,
$columns
);
$parts
=
array
()
;
$parts
=
[]
;
foreach
(
$values
as
$value
)
{
// TODO implement matching here correctly
$value
=
$this
->
quoteValue
(
$value
);
...
...
framework/yii/redis/RecordSchema.php
View file @
8542448f
...
...
@@ -41,7 +41,7 @@ class RecordSchema extends TableSchema
throw
new
InvalidConfigException
(
'primaryKey of RecordSchema must not be empty.'
);
}
if
(
!
is_array
(
$this
->
primaryKey
))
{
$this
->
primaryKey
=
array
(
$this
->
primaryKey
)
;
$this
->
primaryKey
=
[
$this
->
primaryKey
]
;
}
foreach
(
$this
->
primaryKey
as
$pk
)
{
if
(
!
isset
(
$this
->
columns
[
$pk
]))
{
...
...
tests/unit/data/ar/redis/Customer.php
View file @
8542448f
...
...
@@ -16,12 +16,12 @@ class Customer extends ActiveRecord
*/
public
function
getOrders
()
{
return
$this
->
hasMany
(
'Order'
,
array
(
'customer_id'
=>
'id'
)
);
return
$this
->
hasMany
(
Order
::
className
(),
[
'customer_id'
=>
'id'
]
);
}
public
static
function
active
(
$query
)
{
$query
->
andWhere
(
array
(
'status'
=>
1
)
);
$query
->
andWhere
(
[
'status'
=>
1
]
);
}
public
static
function
getRecordSchema
()
...
...
tests/unit/data/ar/redis/Item.php
View file @
8542448f
...
...
@@ -8,15 +8,15 @@ class Item extends ActiveRecord
{
public
static
function
getRecordSchema
()
{
return
new
RecordSchema
(
array
(
return
new
RecordSchema
(
[
'name'
=>
'item'
,
'primaryKey'
=>
array
(
'id'
)
,
'primaryKey'
=>
[
'id'
]
,
'sequenceName'
=>
'id'
,
'columns'
=>
array
(
'columns'
=>
[
'id'
=>
'integer'
,
'name'
=>
'string'
,
'category_id'
=>
'integer'
)
)
);
]
]
);
}
}
\ No newline at end of file
tests/unit/data/ar/redis/Order.php
View file @
8542448f
...
...
@@ -8,17 +8,17 @@ class Order extends ActiveRecord
{
public
function
getCustomer
()
{
return
$this
->
hasOne
(
'Customer'
,
array
(
'id'
=>
'customer_id'
)
);
return
$this
->
hasOne
(
Customer
::
className
(),
[
'id'
=>
'customer_id'
]
);
}
public
function
getOrderItems
()
{
return
$this
->
hasMany
(
'OrderItem'
,
array
(
'order_id'
=>
'id'
)
);
return
$this
->
hasMany
(
OrderItem
::
className
(),
[
'order_id'
=>
'id'
]
);
}
public
function
getItems
()
{
return
$this
->
hasMany
(
'Item'
,
array
(
'id'
=>
'item_id'
)
)
return
$this
->
hasMany
(
Item
::
className
(),
[
'id'
=>
'item_id'
]
)
->
via
(
'orderItems'
,
function
(
$q
)
{
// additional query configuration
});
...
...
@@ -26,9 +26,9 @@ class Order extends ActiveRecord
public
function
getBooks
()
{
return
$this
->
hasMany
(
'Item'
,
array
(
'id'
=>
'item_id'
)
)
->
via
(
'orderItems'
,
array
(
'order_id'
=>
'id'
)
);
//->where(
array('category_id' => 1)
);
return
$this
->
hasMany
(
Item
::
className
(),
[
'id'
=>
'item_id'
]
)
->
via
(
'orderItems'
,
[
'order_id'
=>
'id'
]
);
//->where(
['category_id' => 1]
);
}
public
function
beforeSave
(
$insert
)
...
...
@@ -46,7 +46,7 @@ class Order extends ActiveRecord
{
return
new
RecordSchema
(
array
(
'name'
=>
'orders'
,
'primaryKey'
=>
array
(
'id'
)
,
'primaryKey'
=>
[
'id'
]
,
'columns'
=>
array
(
'id'
=>
'integer'
,
'customer_id'
=>
'integer'
,
...
...
tests/unit/data/ar/redis/OrderItem.php
View file @
8542448f
...
...
@@ -8,19 +8,19 @@ class OrderItem extends ActiveRecord
{
public
function
getOrder
()
{
return
$this
->
hasOne
(
'Order'
,
array
(
'id'
=>
'order_id'
)
);
return
$this
->
hasOne
(
Order
::
className
(),
[
'id'
=>
'order_id'
]
);
}
public
function
getItem
()
{
return
$this
->
hasOne
(
'Item'
,
array
(
'id'
=>
'item_id'
)
);
return
$this
->
hasOne
(
Item
::
className
(),
[
'id'
=>
'item_id'
]
);
}
public
static
function
getRecordSchema
()
{
return
new
RecordSchema
(
array
(
'name'
=>
'order_item'
,
'primaryKey'
=>
array
(
'order_id'
,
'item_id'
)
,
'primaryKey'
=>
[
'order_id'
,
'item_id'
]
,
'columns'
=>
array
(
'order_id'
=>
'integer'
,
'item_id'
=>
'integer'
,
...
...
tests/unit/framework/redis/ActiveRecordTest.php
View file @
8542448f
...
...
@@ -10,6 +10,9 @@ use yiiunit\data\ar\redis\OrderItem;
use
yiiunit\data\ar\redis\Order
;
use
yiiunit\data\ar\redis\Item
;
/**
* @group redis
*/
class
ActiveRecordTest
extends
RedisTestCase
{
public
function
setUp
()
...
...
@@ -18,61 +21,61 @@ class ActiveRecordTest extends RedisTestCase
ActiveRecord
::
$db
=
$this
->
getConnection
();
$customer
=
new
Customer
();
$customer
->
setAttributes
(
array
(
'email'
=>
'user1@example.com'
,
'name'
=>
'user1'
,
'address'
=>
'address1'
,
'status'
=>
1
)
,
false
);
$customer
->
setAttributes
(
[
'email'
=>
'user1@example.com'
,
'name'
=>
'user1'
,
'address'
=>
'address1'
,
'status'
=>
1
]
,
false
);
$customer
->
save
(
false
);
$customer
=
new
Customer
();
$customer
->
setAttributes
(
array
(
'email'
=>
'user2@example.com'
,
'name'
=>
'user2'
,
'address'
=>
'address2'
,
'status'
=>
1
)
,
false
);
$customer
->
setAttributes
(
[
'email'
=>
'user2@example.com'
,
'name'
=>
'user2'
,
'address'
=>
'address2'
,
'status'
=>
1
]
,
false
);
$customer
->
save
(
false
);
$customer
=
new
Customer
();
$customer
->
setAttributes
(
array
(
'email'
=>
'user3@example.com'
,
'name'
=>
'user3'
,
'address'
=>
'address3'
,
'status'
=>
2
)
,
false
);
$customer
->
setAttributes
(
[
'email'
=>
'user3@example.com'
,
'name'
=>
'user3'
,
'address'
=>
'address3'
,
'status'
=>
2
]
,
false
);
$customer
->
save
(
false
);
// INSERT INTO tbl_category (name) VALUES ('Books');
// INSERT INTO tbl_category (name) VALUES ('Movies');
$item
=
new
Item
();
$item
->
setAttributes
(
array
(
'name'
=>
'Agile Web Application Development with Yii1.1 and PHP5'
,
'category_id'
=>
1
)
,
false
);
$item
->
setAttributes
(
[
'name'
=>
'Agile Web Application Development with Yii1.1 and PHP5'
,
'category_id'
=>
1
]
,
false
);
$item
->
save
(
false
);
$item
=
new
Item
();
$item
->
setAttributes
(
array
(
'name'
=>
'Yii 1.1 Application Development Cookbook'
,
'category_id'
=>
1
)
,
false
);
$item
->
setAttributes
(
[
'name'
=>
'Yii 1.1 Application Development Cookbook'
,
'category_id'
=>
1
]
,
false
);
$item
->
save
(
false
);
$item
=
new
Item
();
$item
->
setAttributes
(
array
(
'name'
=>
'Ice Age'
,
'category_id'
=>
2
)
,
false
);
$item
->
setAttributes
(
[
'name'
=>
'Ice Age'
,
'category_id'
=>
2
]
,
false
);
$item
->
save
(
false
);
$item
=
new
Item
();
$item
->
setAttributes
(
array
(
'name'
=>
'Toy Story'
,
'category_id'
=>
2
)
,
false
);
$item
->
setAttributes
(
[
'name'
=>
'Toy Story'
,
'category_id'
=>
2
]
,
false
);
$item
->
save
(
false
);
$item
=
new
Item
();
$item
->
setAttributes
(
array
(
'name'
=>
'Cars'
,
'category_id'
=>
2
)
,
false
);
$item
->
setAttributes
(
[
'name'
=>
'Cars'
,
'category_id'
=>
2
]
,
false
);
$item
->
save
(
false
);
$order
=
new
Order
();
$order
->
setAttributes
(
array
(
'customer_id'
=>
1
,
'create_time'
=>
1325282384
,
'total'
=>
110.0
)
,
false
);
$order
->
setAttributes
(
[
'customer_id'
=>
1
,
'create_time'
=>
1325282384
,
'total'
=>
110.0
]
,
false
);
$order
->
save
(
false
);
$order
=
new
Order
();
$order
->
setAttributes
(
array
(
'customer_id'
=>
2
,
'create_time'
=>
1325334482
,
'total'
=>
33.0
)
,
false
);
$order
->
setAttributes
(
[
'customer_id'
=>
2
,
'create_time'
=>
1325334482
,
'total'
=>
33.0
]
,
false
);
$order
->
save
(
false
);
$order
=
new
Order
();
$order
->
setAttributes
(
array
(
'customer_id'
=>
2
,
'create_time'
=>
1325502201
,
'total'
=>
40.0
)
,
false
);
$order
->
setAttributes
(
[
'customer_id'
=>
2
,
'create_time'
=>
1325502201
,
'total'
=>
40.0
]
,
false
);
$order
->
save
(
false
);
$orderItem
=
new
OrderItem
();
$orderItem
->
setAttributes
(
array
(
'order_id'
=>
1
,
'item_id'
=>
1
,
'quantity'
=>
1
,
'subtotal'
=>
30.0
)
,
false
);
$orderItem
->
setAttributes
(
[
'order_id'
=>
1
,
'item_id'
=>
1
,
'quantity'
=>
1
,
'subtotal'
=>
30.0
]
,
false
);
$orderItem
->
save
(
false
);
$orderItem
=
new
OrderItem
();
$orderItem
->
setAttributes
(
array
(
'order_id'
=>
1
,
'item_id'
=>
2
,
'quantity'
=>
2
,
'subtotal'
=>
40.0
)
,
false
);
$orderItem
->
setAttributes
(
[
'order_id'
=>
1
,
'item_id'
=>
2
,
'quantity'
=>
2
,
'subtotal'
=>
40.0
]
,
false
);
$orderItem
->
save
(
false
);
$orderItem
=
new
OrderItem
();
$orderItem
->
setAttributes
(
array
(
'order_id'
=>
2
,
'item_id'
=>
4
,
'quantity'
=>
1
,
'subtotal'
=>
10.0
)
,
false
);
$orderItem
->
setAttributes
(
[
'order_id'
=>
2
,
'item_id'
=>
4
,
'quantity'
=>
1
,
'subtotal'
=>
10.0
]
,
false
);
$orderItem
->
save
(
false
);
$orderItem
=
new
OrderItem
();
$orderItem
->
setAttributes
(
array
(
'order_id'
=>
2
,
'item_id'
=>
5
,
'quantity'
=>
1
,
'subtotal'
=>
15.0
)
,
false
);
$orderItem
->
setAttributes
(
[
'order_id'
=>
2
,
'item_id'
=>
5
,
'quantity'
=>
1
,
'subtotal'
=>
15.0
]
,
false
);
$orderItem
->
save
(
false
);
$orderItem
=
new
OrderItem
();
$orderItem
->
setAttributes
(
array
(
'order_id'
=>
2
,
'item_id'
=>
3
,
'quantity'
=>
1
,
'subtotal'
=>
8.0
)
,
false
);
$orderItem
->
setAttributes
(
[
'order_id'
=>
2
,
'item_id'
=>
3
,
'quantity'
=>
1
,
'subtotal'
=>
8.0
]
,
false
);
$orderItem
->
save
(
false
);
$orderItem
=
new
OrderItem
();
$orderItem
->
setAttributes
(
array
(
'order_id'
=>
3
,
'item_id'
=>
2
,
'quantity'
=>
1
,
'subtotal'
=>
40.0
)
,
false
);
$orderItem
->
setAttributes
(
[
'order_id'
=>
3
,
'item_id'
=>
2
,
'quantity'
=>
1
,
'subtotal'
=>
40.0
]
,
false
);
$orderItem
->
save
(
false
);
}
...
...
@@ -97,26 +100,26 @@ class ActiveRecordTest extends RedisTestCase
$this
->
assertEquals
(
'user2'
,
$customer
->
name
);
$customer
=
Customer
::
find
(
5
);
$this
->
assertNull
(
$customer
);
$customer
=
Customer
::
find
(
array
(
'id'
=>
array
(
5
,
6
,
1
))
);
$customer
=
Customer
::
find
(
[
'id'
=>
[
5
,
6
,
1
]]
);
$this
->
assertEquals
(
1
,
count
(
$customer
));
$customer
=
Customer
::
find
()
->
where
(
array
(
'id'
=>
array
(
5
,
6
,
1
))
)
->
one
();
$customer
=
Customer
::
find
()
->
where
(
[
'id'
=>
[
5
,
6
,
1
]]
)
->
one
();
$this
->
assertNotNull
(
$customer
);
// query scalar
$customerName
=
Customer
::
find
()
->
where
(
array
(
'id'
=>
2
)
)
->
scalar
(
'name'
);
$customerName
=
Customer
::
find
()
->
where
(
[
'id'
=>
2
]
)
->
scalar
(
'name'
);
$this
->
assertEquals
(
'user2'
,
$customerName
);
// find by column values
$customer
=
Customer
::
find
(
array
(
'id'
=>
2
,
'name'
=>
'user2'
)
);
$customer
=
Customer
::
find
(
[
'id'
=>
2
,
'name'
=>
'user2'
]
);
$this
->
assertTrue
(
$customer
instanceof
Customer
);
$this
->
assertEquals
(
'user2'
,
$customer
->
name
);
$customer
=
Customer
::
find
(
array
(
'id'
=>
2
,
'name'
=>
'user1'
)
);
$customer
=
Customer
::
find
(
[
'id'
=>
2
,
'name'
=>
'user1'
]
);
$this
->
assertNull
(
$customer
);
$customer
=
Customer
::
find
(
array
(
'id'
=>
5
)
);
$customer
=
Customer
::
find
(
[
'id'
=>
5
]
);
$this
->
assertNull
(
$customer
);
// find by attributes
$customer
=
Customer
::
find
()
->
where
(
array
(
'name'
=>
'user2'
)
)
->
one
();
$customer
=
Customer
::
find
()
->
where
(
[
'name'
=>
'user2'
]
)
->
one
();
$this
->
assertTrue
(
$customer
instanceof
Customer
);
$this
->
assertEquals
(
2
,
$customer
->
id
);
...
...
@@ -131,7 +134,7 @@ class ActiveRecordTest extends RedisTestCase
$this
->
assertEquals
(
2
,
Customer
::
find
()
->
active
()
->
count
());
// asArray
$customer
=
Customer
::
find
()
->
where
(
array
(
'id'
=>
2
)
)
->
asArray
()
->
one
();
$customer
=
Customer
::
find
()
->
where
(
[
'id'
=>
2
]
)
->
asArray
()
->
one
();
$this
->
assertEquals
(
array
(
'id'
=>
'2'
,
'email'
=>
'user2@example.com'
,
...
...
@@ -212,14 +215,14 @@ class ActiveRecordTest extends RedisTestCase
public
function
testFindComplexCondition
()
{
$this
->
assertEquals
(
2
,
Customer
::
find
()
->
where
(
array
(
'OR'
,
array
(
'id'
=>
1
),
array
(
'id'
=>
2
))
)
->
count
());
$this
->
assertEquals
(
2
,
count
(
Customer
::
find
()
->
where
(
array
(
'OR'
,
array
(
'id'
=>
1
),
array
(
'id'
=>
2
))
)
->
all
()));
$this
->
assertEquals
(
2
,
Customer
::
find
()
->
where
(
[
'OR'
,
[
'id'
=>
1
],
[
'id'
=>
2
]]
)
->
count
());
$this
->
assertEquals
(
2
,
count
(
Customer
::
find
()
->
where
(
[
'OR'
,
[
'id'
=>
1
],
[
'id'
=>
2
]]
)
->
all
()));
$this
->
assertEquals
(
2
,
Customer
::
find
()
->
where
(
array
(
'id'
=>
array
(
1
,
2
))
)
->
count
());
$this
->
assertEquals
(
2
,
count
(
Customer
::
find
()
->
where
(
array
(
'id'
=>
array
(
1
,
2
))
)
->
all
()));
$this
->
assertEquals
(
2
,
Customer
::
find
()
->
where
(
[
'id'
=>
[
1
,
2
]]
)
->
count
());
$this
->
assertEquals
(
2
,
count
(
Customer
::
find
()
->
where
(
[
'id'
=>
[
1
,
2
]]
)
->
all
()));
$this
->
assertEquals
(
1
,
Customer
::
find
()
->
where
(
array
(
'AND'
,
array
(
'id'
=>
array
(
2
,
3
)),
array
(
'BETWEEN'
,
'status'
,
2
,
4
))
)
->
count
());
$this
->
assertEquals
(
1
,
count
(
Customer
::
find
()
->
where
(
array
(
'AND'
,
array
(
'id'
=>
array
(
2
,
3
)),
array
(
'BETWEEN'
,
'status'
,
2
,
4
))
)
->
all
()));
$this
->
assertEquals
(
1
,
Customer
::
find
()
->
where
(
[
'AND'
,
[
'id'
=>
[
2
,
3
]],
[
'BETWEEN'
,
'status'
,
2
,
4
]]
)
->
count
());
$this
->
assertEquals
(
1
,
count
(
Customer
::
find
()
->
where
(
[
'AND'
,
[
'id'
=>
[
2
,
3
]],
[
'BETWEEN'
,
'status'
,
2
,
4
]]
)
->
all
()));
}
public
function
testSum
()
...
...
@@ -230,14 +233,14 @@ class ActiveRecordTest extends RedisTestCase
public
function
testFindColumn
()
{
$this
->
assertEquals
(
array
(
'user1'
,
'user2'
,
'user3'
)
,
Customer
::
find
()
->
column
(
'name'
));
// TODO $this->assertEquals(
array('user3', 'user2', 'user1'), Customer::find()->orderBy(array('name' => Query::SORT_DESC)
)->column('name'));
$this
->
assertEquals
(
[
'user1'
,
'user2'
,
'user3'
]
,
Customer
::
find
()
->
column
(
'name'
));
// TODO $this->assertEquals(
['user3', 'user2', 'user1'], Customer::find()->orderBy(['name' => SORT_DESC]
)->column('name'));
}
public
function
testExists
()
{
$this
->
assertTrue
(
Customer
::
find
()
->
where
(
array
(
'id'
=>
2
)
)
->
exists
());
$this
->
assertFalse
(
Customer
::
find
()
->
where
(
array
(
'id'
=>
5
)
)
->
exists
());
$this
->
assertTrue
(
Customer
::
find
()
->
where
(
[
'id'
=>
2
]
)
->
exists
());
$this
->
assertFalse
(
Customer
::
find
()
->
where
(
[
'id'
=>
5
]
)
->
exists
());
}
public
function
testFindLazy
()
...
...
@@ -247,7 +250,7 @@ class ActiveRecordTest extends RedisTestCase
$orders
=
$customer
->
orders
;
$this
->
assertEquals
(
2
,
count
(
$orders
));
$orders
=
$customer
->
getOrders
()
->
where
(
array
(
'id'
=>
3
)
)
->
all
();
$orders
=
$customer
->
getOrders
()
->
where
(
[
'id'
=>
3
]
)
->
all
();
$this
->
assertEquals
(
1
,
count
(
$orders
));
$this
->
assertEquals
(
3
,
$orders
[
0
]
->
id
);
}
...
...
@@ -271,7 +274,7 @@ class ActiveRecordTest extends RedisTestCase
$order
=
Order
::
find
(
1
);
$order
->
id
=
100
;
$this
->
assertEquals
(
array
()
,
$order
->
items
);
$this
->
assertEquals
(
[]
,
$order
->
items
);
}
public
function
testFindEagerViaRelation
()
...
...
@@ -327,13 +330,13 @@ class ActiveRecordTest extends RedisTestCase
$order
=
Order
::
find
(
1
);
$this
->
assertEquals
(
2
,
count
(
$order
->
items
));
$this
->
assertEquals
(
2
,
count
(
$order
->
orderItems
));
$orderItem
=
OrderItem
::
find
(
array
(
'order_id'
=>
1
,
'item_id'
=>
3
)
);
$orderItem
=
OrderItem
::
find
(
[
'order_id'
=>
1
,
'item_id'
=>
3
]
);
$this
->
assertNull
(
$orderItem
);
$item
=
Item
::
find
(
3
);
$order
->
link
(
'items'
,
$item
,
array
(
'quantity'
=>
10
,
'subtotal'
=>
100
)
);
$order
->
link
(
'items'
,
$item
,
[
'quantity'
=>
10
,
'subtotal'
=>
100
]
);
$this
->
assertEquals
(
3
,
count
(
$order
->
items
));
$this
->
assertEquals
(
3
,
count
(
$order
->
orderItems
));
$orderItem
=
OrderItem
::
find
(
array
(
'order_id'
=>
1
,
'item_id'
=>
3
)
);
$orderItem
=
OrderItem
::
find
(
[
'order_id'
=>
1
,
'item_id'
=>
3
]
);
$this
->
assertTrue
(
$orderItem
instanceof
OrderItem
);
$this
->
assertEquals
(
10
,
$orderItem
->
quantity
);
$this
->
assertEquals
(
100
,
$orderItem
->
subtotal
);
...
...
@@ -394,7 +397,7 @@ class ActiveRecordTest extends RedisTestCase
$this
->
assertEquals
(
'user3'
,
$customer
->
name
);
$ret
=
Customer
::
updateAll
(
array
(
'name'
=>
'temp'
,
),
array
(
'id'
=>
3
)
);
),
[
'id'
=>
3
]
);
$this
->
assertEquals
(
1
,
$ret
);
$customer
=
Customer
::
find
(
3
);
$this
->
assertEquals
(
'temp'
,
$customer
->
name
);
...
...
@@ -403,17 +406,17 @@ class ActiveRecordTest extends RedisTestCase
public
function
testUpdateCounters
()
{
// updateCounters
$pk
=
array
(
'order_id'
=>
2
,
'item_id'
=>
4
)
;
$pk
=
[
'order_id'
=>
2
,
'item_id'
=>
4
]
;
$orderItem
=
OrderItem
::
find
(
$pk
);
$this
->
assertEquals
(
1
,
$orderItem
->
quantity
);
$ret
=
$orderItem
->
updateCounters
(
array
(
'quantity'
=>
-
1
)
);
$ret
=
$orderItem
->
updateCounters
(
[
'quantity'
=>
-
1
]
);
$this
->
assertTrue
(
$ret
);
$this
->
assertEquals
(
0
,
$orderItem
->
quantity
);
$orderItem
=
OrderItem
::
find
(
$pk
);
$this
->
assertEquals
(
0
,
$orderItem
->
quantity
);
// updateAllCounters
$pk
=
array
(
'order_id'
=>
1
,
'item_id'
=>
2
)
;
$pk
=
[
'order_id'
=>
1
,
'item_id'
=>
2
]
;
$orderItem
=
OrderItem
::
find
(
$pk
);
$this
->
assertEquals
(
2
,
$orderItem
->
quantity
);
$ret
=
OrderItem
::
updateAllCounters
(
array
(
...
...
@@ -429,7 +432,7 @@ class ActiveRecordTest extends RedisTestCase
public
function
testUpdatePk
()
{
// updateCounters
$pk
=
array
(
'order_id'
=>
2
,
'item_id'
=>
4
)
;
$pk
=
[
'order_id'
=>
2
,
'item_id'
=>
4
]
;
$orderItem
=
OrderItem
::
find
(
$pk
);
$this
->
assertEquals
(
2
,
$orderItem
->
order_id
);
$this
->
assertEquals
(
4
,
$orderItem
->
item_id
);
...
...
@@ -439,7 +442,7 @@ class ActiveRecordTest extends RedisTestCase
$orderItem
->
save
();
$this
->
assertNull
(
OrderItem
::
find
(
$pk
));
$this
->
assertNotNull
(
OrderItem
::
find
(
array
(
'order_id'
=>
2
,
'item_id'
=>
10
)
));
$this
->
assertNotNull
(
OrderItem
::
find
(
[
'order_id'
=>
2
,
'item_id'
=>
10
]
));
}
public
function
testDelete
()
...
...
tests/unit/framework/redis/RedisConnectionTest.php
View file @
8542448f
...
...
@@ -4,6 +4,9 @@ namespace yiiunit\framework\redis;
use
yii\redis\Connection
;
/**
* @group redis
*/
class
RedisConnectionTest
extends
RedisTestCase
{
/**
...
...
tests/unit/framework/redis/RedisTestCase.php
View file @
8542448f
...
...
@@ -8,7 +8,7 @@ use yiiunit\TestCase;
/**
* RedisTestCase is the base class for all redis related test cases
*/
class
RedisTestCase
extends
TestCase
abstract
class
RedisTestCase
extends
TestCase
{
protected
function
setUp
()
{
...
...
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