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
965fe5c4
Commit
965fe5c4
authored
Feb 25, 2012
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
...
parent
cf10943c
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1525 additions
and
980 deletions
+1525
-980
ActiveQuery.php
framework/db/ar/ActiveQuery.php
+453
-0
ActiveRecord.php
framework/db/ar/ActiveRecord.php
+334
-254
ActiveRecordBehavior.php
framework/db/ar/ActiveRecordBehavior.php
+25
-4
ActiveRelation.php
framework/db/ar/ActiveRelation.php
+39
-42
BaseQuery.php
framework/db/dao/BaseQuery.php
+635
-0
Command.php
framework/db/dao/Command.php
+5
-21
Connection.php
framework/db/dao/Connection.php
+4
-7
Query.php
framework/db/dao/Query.php
+18
-634
QueryBuilder.php
framework/db/dao/QueryBuilder.php
+12
-18
No files found.
framework/db/ar/ActiveQuery.php
0 → 100644
View file @
965fe5c4
<?php
/**
* ActiveFinder class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\ar
;
use
yii\base\VectorIterator
;
use
yii\db\dao\BaseQuery
;
use
yii\db\Exception
;
/**
* ActiveFinder.php is ...
* todo: add SQL monitor
* todo: better handling on join() support in QueryBuilder: use regexp to detect table name and quote it
* todo: do not support anonymous parameter binding
* todo: add ActiveFinderBuilder
* todo: quote join/on part of the relational query
* todo: modify QueryBuilder about join() methods
* todo: unify ActiveFinder and ActiveRelation in query building process
* todo: intelligent table aliasing (first table name, then relation name, finally t?)
* todo: allow using tokens in primary query fragments
* todo: findBySql
* todo: base limited
* todo: lazy loading
* todo: scope
* todo: test via option
* todo: count, sum, exists
*
* @property integer $count
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
ActiveQuery
extends
BaseQuery
implements
\IteratorAggregate
,
\ArrayAccess
,
\Countable
{
/**
* @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 the table alias to be used for query
*/
public
$tableAlias
;
/**
* @var string the name of the column that the result should be indexed by.
* This is only useful when the query result is returned as an array.
*/
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 list of scopes that should be applied to this query
*/
public
$scopes
;
/**
* @var array list of query results
*/
public
$records
;
public
$sql
;
/**
* @param string $modelClass the name of the ActiveRecord class.
*/
public
function
__construct
(
$modelClass
)
{
$this
->
modelClass
=
$modelClass
;
}
public
function
asArray
(
$value
=
true
)
{
$this
->
asArray
=
$value
;
return
$this
;
}
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
;
}
public
function
indexBy
(
$column
)
{
$this
->
indexBy
=
$column
;
return
$this
;
}
public
function
tableAlias
(
$value
)
{
$this
->
tableAlias
=
$value
;
return
$this
;
}
/**
* 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
()
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
return
$this
->
records
;
}
/**
* Executes query and returns a single row of result.
* @return null|array|ActiveRecord the 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
()
{
if
(
$this
->
records
===
null
)
{
// todo: load only one record
$this
->
records
=
$this
->
findRecords
();
}
return
isset
(
$this
->
records
[
0
])
?
$this
->
records
[
0
]
:
null
;
}
public
function
value
()
{
return
0
;
}
public
function
exists
()
{
return
$this
->
select
(
array
(
'1'
))
->
asArray
(
true
)
->
one
()
!==
null
;
}
/**
* Returns the database connection used by this query.
* This method returns the connection used by the [[modelClass]].
* @return \yii\db\dao\Connection the database connection used by this query
*/
public
function
getDbConnection
()
{
$class
=
$this
->
modelClass
;
return
$class
::
getDbConnection
();
}
/**
* Returns the number of items in the vector.
* @return integer the number of items in the vector
*/
public
function
getCount
()
{
return
$this
->
count
();
}
/**
* Sets the parameters about query caching.
* This is a shortcut method to {@link CDbConnection::cache()}.
* It changes the query caching parameter of the {@link dbConnection} instance.
* @param integer $duration the number of seconds that query results may remain valid in cache.
* If this is 0, the caching will be disabled.
* @param CCacheDependency $dependency the dependency that will be used when saving the query results into cache.
* @param integer $queryCount number of SQL queries that need to be cached after calling this method. Defaults to 1,
* meaning that the next SQL query will be cached.
* @return ActiveRecord the active record instance itself.
*/
public
function
cache
(
$duration
,
$dependency
=
null
,
$queryCount
=
1
)
{
$this
->
getDbConnection
()
->
cache
(
$duration
,
$dependency
,
$queryCount
);
return
$this
;
}
/**
* Returns an iterator for traversing the items in the vector.
* This method is required by the SPL interface `IteratorAggregate`.
* It will be implicitly called when you use `foreach` to traverse the vector.
* @return VectorIterator an iterator for traversing the items in the vector.
*/
public
function
getIterator
()
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
return
new
VectorIterator
(
$this
->
records
);
}
/**
* Returns the number of items in the vector.
* This method is required by the SPL `Countable` interface.
* It will be implicitly called when you use `count($vector)`.
* @return integer number of items in the vector.
*/
public
function
count
()
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
return
count
(
$this
->
records
);
}
/**
* Returns a value indicating whether there is an item at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `isset($vector[$offset])`.
* @param integer $offset the offset to be checked
* @return boolean whether there is an item at the specified offset.
*/
public
function
offsetExists
(
$offset
)
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
return
isset
(
$this
->
records
[
$offset
]);
}
/**
* Returns the item at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$value = $vector[$offset];`.
* This is equivalent to [[itemAt]].
* @param integer $offset the offset to retrieve item.
* @return ActiveRecord the item at the offset
* @throws Exception if the offset is out of range
*/
public
function
offsetGet
(
$offset
)
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
return
isset
(
$this
->
records
[
$offset
])
?
$this
->
records
[
$offset
]
:
null
;
}
/**
* Sets the item at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$vector[$offset] = $item;`.
* If the offset is null or equal to the number of the existing items,
* the new item will be appended to the vector.
* Otherwise, the existing item at the offset will be replaced with the new item.
* @param integer $offset the offset to set item
* @param ActiveRecord $item the item value
* @throws Exception if the offset is out of range, or the vector is read only.
*/
public
function
offsetSet
(
$offset
,
$item
)
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
$this
->
records
[
$offset
]
=
$item
;
}
/**
* Unsets the item at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `unset($vector[$offset])`.
* This is equivalent to [[removeAt]].
* @param integer $offset the offset to unset item
* @throws Exception if the offset is out of range, or the vector is read only.
*/
public
function
offsetUnset
(
$offset
)
{
if
(
$this
->
records
===
null
)
{
$this
->
records
=
$this
->
findRecords
();
}
unset
(
$this
->
records
[
$offset
]);
}
public
function
joinWith
()
{
// todo: inner join with one or multiple relations as filters
}
protected
function
findRecords
()
{
if
(
!
empty
(
$this
->
with
))
{
// todo: handle findBySql() and limit cases
$joinTree
=
$this
->
buildRelationalQuery
();
}
if
(
$this
->
sql
===
null
)
{
$this
->
initFrom
(
$this
->
query
);
$command
=
$this
->
query
->
createCommand
(
$this
->
getDbConnection
());
$this
->
sql
=
$command
->
getSql
();
}
else
{
$command
=
$this
->
getDbConnection
()
->
createCommand
(
$this
->
sql
);
$command
->
bindValues
(
$this
->
query
->
params
);
}
$rows
=
$command
->
queryAll
();
if
(
isset
(
$joinTree
))
{
foreach
(
$rows
as
$row
)
{
$joinTree
->
populateData
(
$row
);
}
return
array_values
(
$joinTree
->
records
);
}
if
(
$this
->
asArray
)
{
if
(
$this
->
indexBy
===
null
)
{
return
$rows
;
}
$records
=
array
();
foreach
(
$rows
as
$row
)
{
$records
[
$row
[
$this
->
indexBy
]]
=
$row
;
}
return
$records
;
}
else
{
$records
=
array
();
$class
=
$this
->
modelClass
;
if
(
$this
->
indexBy
===
null
)
{
foreach
(
$rows
as
$row
)
{
$records
[]
=
$class
::
populateData
(
$row
);
}
}
else
{
$attribute
=
$this
->
indexBy
;
foreach
(
$rows
as
$row
)
{
$record
=
$class
::
populateData
(
$row
);
$records
[
$record
->
$attribute
]
=
$record
;
}
}
return
$records
;
}
}
protected
function
initFrom
(
$query
)
{
if
(
$query
->
from
===
null
)
{
$modelClass
=
$this
->
modelClass
;
$tableName
=
$modelClass
::
tableName
();
if
(
$this
->
tableAlias
!==
null
)
{
$tableName
.=
' '
.
$this
->
tableAlias
;
}
$query
->
from
=
array
(
$tableName
);
}
}
protected
function
buildRelationalQuery
()
{
$joinTree
=
new
JoinElement
(
$this
,
null
,
null
);
$this
->
buildJoinTree
(
$joinTree
,
$this
->
with
);
$this
->
buildTableAlias
(
$joinTree
);
$query
=
new
Query
;
foreach
(
$joinTree
->
children
as
$child
)
{
$child
->
buildQuery
(
$query
);
}
$select
=
$joinTree
->
buildSelect
(
$this
->
query
->
select
);
if
(
!
empty
(
$query
->
select
))
{
$this
->
query
->
select
=
array_merge
(
$select
,
$query
->
select
);
}
else
{
$this
->
query
->
select
=
$select
;
}
if
(
!
empty
(
$query
->
where
))
{
$this
->
query
->
andWhere
(
'('
.
implode
(
') AND ('
,
$query
->
where
)
.
')'
);
}
if
(
!
empty
(
$query
->
having
))
{
$this
->
query
->
andHaving
(
'('
.
implode
(
') AND ('
,
$query
->
having
)
.
')'
);
}
if
(
!
empty
(
$query
->
join
))
{
if
(
$this
->
query
->
join
===
null
)
{
$this
->
query
->
join
=
$query
->
join
;
}
else
{
$this
->
query
->
join
=
array_merge
(
$this
->
query
->
join
,
$query
->
join
);
}
}
if
(
!
empty
(
$query
->
orderBy
))
{
$this
->
query
->
addOrderBy
(
$query
->
orderBy
);
}
if
(
!
empty
(
$query
->
groupBy
))
{
$this
->
query
->
addGroupBy
(
$query
->
groupBy
);
}
if
(
!
empty
(
$query
->
params
))
{
$this
->
query
->
addParams
(
$query
->
params
);
}
return
$joinTree
;
}
/**
* @param JoinElement $parent
* @param array|string $with
* @param array $config
* @return null|JoinElement
* @throws \yii\db\Exception
*/
protected
function
buildJoinTree
(
$parent
,
$with
,
$config
=
array
())
{
if
(
is_array
(
$with
))
{
foreach
(
$with
as
$name
=>
$value
)
{
if
(
is_string
(
$value
))
{
$this
->
buildJoinTree
(
$parent
,
$value
);
}
elseif
(
is_string
(
$name
)
&&
is_array
(
$value
))
{
$this
->
buildJoinTree
(
$parent
,
$name
,
$value
);
}
}
return
null
;
}
if
((
$pos
=
strrpos
(
$with
,
'.'
))
!==
false
)
{
$parent
=
$this
->
buildJoinTree
(
$parent
,
substr
(
$with
,
0
,
$pos
));
$with
=
substr
(
$with
,
$pos
+
1
);
}
if
(
isset
(
$parent
->
children
[
$with
]))
{
$child
=
$parent
->
children
[
$with
];
$child
->
joinOnly
=
false
;
}
else
{
$modelClass
=
$parent
->
relation
->
modelClass
;
$relations
=
$modelClass
::
getMetaData
()
->
relations
;
if
(
!
isset
(
$relations
[
$with
]))
{
throw
new
Exception
(
"
$modelClass
has no relation named '
$with
'."
);
}
$relation
=
clone
$relations
[
$with
];
if
(
$relation
->
via
!==
null
&&
isset
(
$relations
[
$relation
->
via
]))
{
$relation
->
via
=
null
;
$parent2
=
$this
->
buildJoinTree
(
$parent
,
$relation
->
via
);
if
(
$parent2
->
joinOnly
===
null
)
{
$parent2
->
joinOnly
=
true
;
}
$child
=
new
JoinElement
(
$relation
,
$parent2
,
$parent
);
}
else
{
$child
=
new
JoinElement
(
$relation
,
$parent
,
$parent
);
}
}
foreach
(
$config
as
$name
=>
$value
)
{
$child
->
relation
->
$name
=
$value
;
}
return
$child
;
}
protected
function
buildTableAlias
(
$element
,
&
$count
=
0
)
{
if
(
$element
->
relation
->
tableAlias
===
null
)
{
$element
->
relation
->
tableAlias
=
't'
.
(
$count
++
);
}
foreach
(
$element
->
children
as
$child
)
{
$this
->
buildTableAlias
(
$child
,
$count
);
}
}
}
framework/db/ar/ActiveRecord.php
View file @
965fe5c4
...
...
@@ -38,6 +38,10 @@ abstract class ActiveRecord extends Model
* @var array old attribute values indexed by attribute names.
*/
private
$_oldAttributes
;
/**
* @var array related records indexed by relation names.
*/
private
$_related
;
/**
* Returns the metadata for this AR class.
...
...
@@ -61,104 +65,167 @@ abstract class ActiveRecord extends Model
}
/**
* Creates an [[Active
Finder
]] instance for query purpose.
* Creates an [[Active
Query
]] instance for query purpose.
*
* Because [[Active
Finder
]] implements a set of query building methods,
* additional query conditions can be specified by calling the
se methods
.
* Because [[Active
Query
]] implements a set of query building methods,
* additional query conditions can be specified by calling the
methods of [[ActiveQuery]]
.
*
* Below are some usage examples:
*
* ~~~
* // find all customers
* $customers = Customer::find()->all();
* // find a single customer whose
ID
is 10
* // find a single customer whose
primary key value
is 10
* $customer = Customer::find(10)->one();
* // find all active customers and order them by their age:
* $customers = Customer::find(array('status' => 1))->orderBy('age')->all();
* $customers = Customer::find()
* ->where(array('status' => 1))
* ->orderBy('age')
* ->all();
* // or alternatively:
* $customers = Customer::find(array(
* 'where' => array('status' => 1),
* 'orderBy' => 'age',
* ))->all();
* ~~~
*
* @param mixed $q the query parameter. This can be one of the followings:
*
* - a scalar value (integer, string): query by a single primary key value.
* - an array of name-value pairs: query by a set of column values.
* - a [[Query]] object: query by a full query object.
* - a scalar value (integer or string): query by a single primary key value.
* - an array of name-value pairs: it will be used to configure the [[ActiveQuery]] object.
*
* @return ActiveFinder the [[ActiveFinder]] instance for query purpose.
* @throws Exception if the query parameter is invalid.
* @return ActiveQuery the [[ActiveQuery]] instance for query purpose.
*/
public
static
function
find
(
$q
=
null
)
{
$finder
=
static
::
createActiveFinder
();
if
(
$q
instanceof
Query
)
{
$finder
->
query
=
$q
;
}
elseif
(
is_array
(
$q
))
{
// query by a set of column values
$finder
->
where
(
$q
);
$query
=
static
::
createActiveQuery
();
if
(
is_array
(
$q
))
{
foreach
(
$q
as
$name
=>
$value
)
{
$query
->
$name
=
$value
;
}
}
elseif
(
$q
!==
null
)
{
// query by primary key
$primaryKey
=
static
::
getMetaData
()
->
table
->
primaryKey
;
if
(
count
(
$primaryKey
)
===
1
)
{
$finder
->
where
(
array
(
$primaryKey
[
0
]
=>
$q
));
}
else
{
throw
new
Exception
(
'Multiple values are required to query by composite primary keys.'
);
}
$query
->
where
(
array
(
$primaryKey
[
0
]
=>
$q
));
}
return
$
finder
;
return
$
query
;
}
/**
* Creates an [[Active
Finder
]] instance and query by a given SQL statement.
* Creates an [[Active
Query
]] instance and query by a given SQL statement.
* Note that because the SQL statement is already specified, calling further
* query methods (such as `where()`, `orderBy()`) on [[ActiveFinder]] will have no effect.
* query methods (such as `where()`, `orderBy()`) on [[ActiveQuery]] will have no effect.
* Methods such as `with()`, `asArray()` can still be called though.
* @param string $sql the SQL statement to be executed
* @param array $params parameters to be bound to the SQL statement during execution.
* @return Active
Finder the [[ActiveFinder
]] instance
* @return Active
Query the [[ActiveQuery
]] instance
*/
public
static
function
findBySql
(
$sql
,
$params
=
array
())
{
$finder
=
static
::
createActiveFinder
();
$finder
->
sql
=
$sql
;
return
$finder
->
params
(
$params
);
$query
=
static
::
createActiveQuery
();
$query
->
sql
=
$sql
;
return
$query
->
params
(
$params
);
}
/**
* Performs a COUNT query for this AR class.
*
* Below are some usage examples:
*
* ~~~
* // count the total number of customers
* echo Customer::count();
* // count the number of customers whose primary key value is 10.
* echo Customer::count(10);
* // count the number of active customers:
* echo Customer::count(array(
* 'where' => array('status' => 1),
* ));
* ~~~
*
* @param mixed $q the query parameter. This can be one of the followings:
*
* - a scalar value (integer or string): query by a single primary key value.
* - an array of name-value pairs: it will be used to configure the [[ActiveQuery]] object for query purpose.
*
* @return integer the counting result
*/
public
static
function
count
(
$q
=
null
)
{
$query
=
static
::
createActiveQuery
();
if
(
is_array
(
$q
))
{
foreach
(
$q
as
$name
=>
$value
)
{
$query
->
$name
=
$value
;
}
}
elseif
(
$q
!==
null
)
{
// query by primary key
$primaryKey
=
static
::
getMetaData
()
->
table
->
primaryKey
;
$query
->
where
(
array
(
$primaryKey
[
0
]
=>
$q
));
}
if
(
$query
->
select
===
null
)
{
$query
->
select
=
'COUNT(*)'
;
}
return
$query
->
value
();
}
/**
* Updates the whole table using the provided attribute values and conditions.
* @param array $attributes attribute values to be saved into the table
* @param string|array $condition the conditions that will be put in the WHERE part.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return integer the number of rows updated
*/
public
static
function
updateAll
(
$attributes
,
$condition
=
''
,
$params
=
array
())
{
$class
=
get_called_class
();
$query
=
new
Query
;
$query
->
update
(
$class
::
tableName
(),
$attributes
,
$condition
,
$params
);
return
$query
->
createCommand
(
$class
::
getDbConnection
())
->
execute
();
$query
->
update
(
static
::
tableName
(),
$attributes
,
$condition
,
$params
);
return
$query
->
createCommand
(
static
::
getDbConnection
())
->
execute
();
}
public
static
function
updateCounters
(
$counters
,
$condition
=
''
,
$params
=
array
())
/**
* Updates the whole table using the provided counter values and conditions.
* @param array $counters the counters to be updated (attribute name => increment value).
* @param string|array $condition the conditions that will be put in the WHERE part.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return integer the number of rows updated
*/
public
static
function
updateAllCounters
(
$counters
,
$condition
=
''
,
$params
=
array
())
{
$class
=
get_called_class
();
$db
=
$class
::
getDbConnection
();
$db
=
static
::
getDbConnection
();
foreach
(
$counters
as
$name
=>
$value
)
{
$value
=
(
int
)
$value
;
$quotedName
=
$db
->
quoteColumnName
(
$name
,
true
);
$counters
[
$name
]
=
new
Expression
(
$value
>=
0
?
"
$quotedName
+
$value
"
:
"
$quotedName$value
"
);
}
$query
=
new
Query
;
$query
->
update
(
$class
::
tableName
(),
$counters
,
$condition
,
$params
);
return
$query
->
createCommand
(
$
class
::
getDbConnection
()
)
->
execute
();
$query
->
update
(
static
::
tableName
(),
$counters
,
$condition
,
$params
);
return
$query
->
createCommand
(
$
db
)
->
execute
();
}
/**
* Deletes rows in the table using the provided conditions.
* @param string|array $condition the conditions that will be put in the WHERE part.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return integer the number of rows updated
*/
public
static
function
deleteAll
(
$condition
=
''
,
$params
=
array
())
{
$class
=
get_called_class
();
$query
=
new
Query
;
$query
->
delete
(
$class
::
tableName
(),
$condition
,
$params
);
return
$query
->
createCommand
(
$class
::
getDbConnection
())
->
execute
();
$query
->
delete
(
static
::
tableName
(),
$condition
,
$params
);
return
$query
->
createCommand
(
static
::
getDbConnection
())
->
execute
();
}
/**
* Creates a [[Active
Finder
]] instance.
* This method is
mainly called by [[find()]] and [[findBySql()]]
.
* @return Active
Finder the newly created [[ActiveFinder
]] instance.
* Creates a [[Active
Query
]] instance.
* This method is
called by [[find()]] and [[findBySql()]] to start a SELECT query
.
* @return Active
Query the newly created [[ActiveQuery
]] instance.
*/
public
static
function
createActive
Finder
()
public
static
function
createActive
Query
()
{
return
new
Active
Finder
(
get_called_class
());
return
new
Active
Query
(
get_called_class
());
}
/**
...
...
@@ -175,8 +242,8 @@ abstract class ActiveRecord extends Model
/**
* Declares the primary key name for this AR class.
* This method is meant to be overridden in case when the table
is not defined with a primary key
* (for some legacy database). If the table
is already defined with
a primary key,
* This method is meant to be overridden in case when the table
has no primary key defined
* (for some legacy database). If the table
already has
a primary key,
* you do not need to override this method. The default implementation simply returns null,
* meaning using the primary key defined in the database table.
* @return string|array the primary key of the associated database table.
...
...
@@ -193,7 +260,7 @@ abstract class ActiveRecord extends Model
*
* Child classes may override this method to specify their relations.
*
* The following shows how to declare relations for a `Programmer` AR class:
* The following
code
shows how to declare relations for a `Programmer` AR class:
*
* ~~~
* return array(
...
...
@@ -350,14 +417,17 @@ abstract class ActiveRecord extends Model
*/
public
function
__get
(
$name
)
{
if
(
isset
(
$this
->
_attributes
[
$name
])
||
array_key_exists
(
$name
,
$this
->
_attributes
)
)
{
if
(
isset
(
$this
->
_attributes
[
$name
]))
{
return
$this
->
_attributes
[
$name
];
}
else
{
}
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
table
->
columns
[
$name
]))
{
return
null
;
}
elseif
(
isset
(
$md
->
relations
[
$name
]))
{
return
$this
->
_attributes
[
$name
]
=
$this
->
loadRelatedRecord
(
$md
->
relations
[
$name
]);
if
(
array_key_exists
(
$name
,
$this
->
_related
))
{
return
$this
->
_related
[
$name
];
}
else
{
return
$this
->
_related
[
$name
]
=
$this
->
loadRelatedRecord
(
$md
->
relations
[
$name
]);
}
}
return
parent
::
__get
(
$name
);
...
...
@@ -372,8 +442,10 @@ abstract class ActiveRecord extends Model
public
function
__set
(
$name
,
$value
)
{
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
table
->
columns
[
$name
])
||
isset
(
$md
->
relations
[
$name
])
)
{
if
(
isset
(
$md
->
table
->
columns
[
$name
]))
{
$this
->
_attributes
[
$name
]
=
$value
;
}
elseif
(
isset
(
$md
->
relations
[
$name
]))
{
$this
->
_related
[
$name
]
=
$value
;
}
else
{
parent
::
__set
(
$name
,
$value
);
}
...
...
@@ -388,9 +460,11 @@ abstract class ActiveRecord extends Model
*/
public
function
__isset
(
$name
)
{
if
(
isset
(
$this
->
_attributes
[
$name
]))
{
if
(
isset
(
$this
->
_attributes
[
$name
])
||
isset
(
$this
->
_related
[
$name
])
)
{
return
true
;
}
elseif
(
isset
(
$this
->
getMetaData
()
->
table
->
columns
[
$name
])
||
isset
(
$this
->
getMetaData
()
->
relations
[
$name
]))
{
}
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
table
->
columns
[
$name
])
||
isset
(
$md
->
relations
[
$name
]))
{
return
false
;
}
else
{
return
parent
::
__isset
(
$name
);
...
...
@@ -406,8 +480,10 @@ abstract class ActiveRecord extends Model
public
function
__unset
(
$name
)
{
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
table
->
columns
[
$name
])
||
isset
(
$md
->
relations
[
$name
])
)
{
if
(
isset
(
$md
->
table
->
columns
[
$name
]))
{
unset
(
$this
->
_attributes
[
$name
]);
}
elseif
(
isset
(
$md
->
relations
[
$name
]))
{
unset
(
$this
->
_related
[
$name
]);
}
else
{
parent
::
__unset
(
$name
);
}
...
...
@@ -432,20 +508,20 @@ abstract class ActiveRecord extends Model
/**
* Initializes the internal storage for the relation.
* This method is internally used by [[Active
Finder
]] when populating relation data.
* This method is internally used by [[Active
Query
]] when populating relation data.
* @param ActiveRelation $relation the relation object
*/
public
function
initRelation
(
$relation
)
{
$this
->
_
attributes
[
$relation
->
name
]
=
$relation
->
hasMany
?
array
()
:
null
;
$this
->
_
related
[
$relation
->
name
]
=
$relation
->
hasMany
?
array
()
:
null
;
}
public
function
addRelatedRecord
(
$relation
,
$record
)
{
if
(
$relation
->
hasMany
)
{
$this
->
_
attributes
[
$relation
->
name
][]
=
$record
;
$this
->
_
related
[
$relation
->
name
][]
=
$record
;
}
else
{
$this
->
_
attributes
[
$relation
->
name
]
=
$record
;
$this
->
_
related
[
$relation
->
name
]
=
$record
;
}
}
...
...
@@ -472,7 +548,7 @@ abstract class ActiveRecord extends Model
}
$relation
=
$md
->
relations
[
$relation
];
}
$finder
=
$this
->
createActive
Finder
();
$finder
=
$this
->
createActive
Query
();
}
/**
...
...
@@ -541,7 +617,7 @@ abstract class ActiveRecord extends Model
}
$names
=
array_flip
(
$names
);
$attributes
=
array
();
if
(
empty
(
$this
->
_oldAttributes
)
)
{
if
(
$this
->
_oldAttributes
===
null
)
{
foreach
(
$this
->
_attributes
as
$name
=>
$value
)
{
if
(
isset
(
$names
[
$name
]))
{
$attributes
[
$name
]
=
$value
;
...
...
@@ -584,6 +660,124 @@ abstract class ActiveRecord extends Model
{
if
(
!
$runValidation
||
$this
->
validate
(
$attributes
))
{
return
$this
->
getIsNewRecord
()
?
$this
->
insert
(
$attributes
)
:
$this
->
update
(
$attributes
);
}
return
false
;
}
/**
* Inserts a row into the table based on this active record attributes.
* If the table's primary key is auto-incremental and is null before insertion,
* it will be populated with the actual value after insertion.
* Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
* After the record is inserted to DB successfully, its {@link isNewRecord} property will be set false,
* and its {@link scenario} property will be set to be 'update'.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the attributes are valid and the record is inserted successfully.
* @throws Exception if the record is not new
*/
public
function
insert
(
$attributes
=
null
)
{
if
(
$this
->
beforeInsert
())
{
$query
=
new
Query
;
$values
=
$this
->
getChangedAttributes
(
$attributes
);
$db
=
$this
->
getDbConnection
();
$command
=
$query
->
insert
(
$this
->
tableName
(),
$values
)
->
createCommand
(
$db
);
if
(
$command
->
execute
())
{
$table
=
$this
->
getMetaData
()
->
table
;
if
(
$table
->
sequenceName
!==
null
)
{
foreach
(
$table
->
primaryKey
as
$name
)
{
if
(
!
isset
(
$this
->
_attributes
[
$name
]))
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
]
=
$db
->
getLastInsertID
(
$table
->
sequenceName
);
break
;
}
}
}
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$value
;
}
$this
->
afterInsert
();
return
true
;
}
}
return
false
;
}
/**
* Updates the row represented by this active record.
* All loaded attributes will be saved to the database.
* Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the update is successful
* @throws Exception if the record is new
*/
public
function
update
(
$attributes
=
null
)
{
if
(
$this
->
getIsNewRecord
())
{
throw
new
Exception
(
'The active record cannot be updated because it is new.'
);
}
if
(
$this
->
beforeUpdate
())
{
$values
=
$this
->
getChangedAttributes
(
$attributes
);
if
(
$values
!==
array
())
{
$this
->
updateAll
(
$values
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
];
}
$this
->
afterUpdate
();
}
return
true
;
}
else
{
return
false
;
}
}
/**
* Saves one or several counter columns for the current AR object.
* Note that this method differs from [[updateAllCounters()]] in that it only
* saves counters for the current AR object.
*
* An example usage is as follows:
*
* ~~~
* $post = Post::find($id)->one();
* $post->updateCounters(array('view_count' => 1));
* ~~~
*
* Use negative values if you want to decrease the counters.
* @param array $counters the counters to be updated (attribute name => increment value)
* @return boolean whether the saving is successful
* @throws Exception if the record is new or any database error
* @see updateAllCounters()
*/
public
function
updateCounters
(
$counters
)
{
if
(
$this
->
getIsNewRecord
())
{
throw
new
Exception
(
'The active record cannot be updated because it is new.'
);
}
$this
->
updateAllCounters
(
$counters
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$counters
as
$name
=>
$value
)
{
$this
->
_attributes
[
$name
]
+=
$value
;
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
];
}
return
true
;
}
/**
* Deletes the row corresponding to this active record.
* @return boolean whether the deletion is successful.
* @throws Exception if the record is new or any database error
*/
public
function
delete
()
{
if
(
$this
->
getIsNewRecord
())
{
throw
new
Exception
(
'The active record cannot be deleted because it is new.'
);
}
if
(
$this
->
beforeDelete
())
{
$result
=
$this
->
deleteAll
(
$this
->
getPrimaryKey
(
true
))
>
0
;
$this
->
_oldAttributes
=
null
;
$this
->
afterDelete
();
return
$result
;
}
else
{
return
false
;
}
...
...
@@ -598,7 +792,7 @@ abstract class ActiveRecord extends Model
*/
public
function
getIsNewRecord
()
{
return
empty
(
$this
->
_oldAttributes
)
;
return
$this
->
_oldAttributes
===
null
;
}
/**
...
...
@@ -608,41 +802,51 @@ abstract class ActiveRecord extends Model
*/
public
function
setIsNewRecord
(
$value
)
{
if
(
$value
)
{
$this
->
_oldAttributes
=
null
;
}
else
{
$this
->
_oldAttributes
=
array
();
foreach
(
$this
->
attributeNames
()
as
$name
)
{
if
(
isset
(
$this
->
_attributes
[
$name
]))
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
];
}
$this
->
_oldAttributes
=
$value
?
null
:
$this
->
_attributes
;
}
/**
* This event is raised before the record is saved.
* By setting [[\yii\base\ModelEvent::isValid]] to be false, the normal [[save()]] will be stopped.
* @param \yii\base\ModelEvent $event the event parameter
*/
public
function
onBeforeInsert
(
$event
)
{
$this
->
raiseEvent
(
'onBeforeInsert'
,
$event
);
}
/**
* This event is raised after the record is saved.
* @param \yii\base\Event $event the event parameter
*/
public
function
onAfterInsert
(
$event
)
{
$this
->
raiseEvent
(
'onAfterInsert'
,
$event
);
}
/**
* This event is raised before the record is saved.
* By setting
{@link ModelEvent::isValid} to be false, the normal {@link save()} process
will be stopped.
* @param ModelEvent $event the event parameter
* By setting
[[\yii\base\ModelEvent::isValid]] to be false, the normal [[save()]]
will be stopped.
* @param
\yii\base\
ModelEvent $event the event parameter
*/
public
function
onBefore
Sav
e
(
$event
)
public
function
onBefore
Updat
e
(
$event
)
{
$this
->
raiseEvent
(
'onBefore
Sav
e'
,
$event
);
$this
->
raiseEvent
(
'onBefore
Updat
e'
,
$event
);
}
/**
* This event is raised after the record is saved.
* @param Event $event the event parameter
* @param
\yii\base\
Event $event the event parameter
*/
public
function
onAfter
Sav
e
(
$event
)
public
function
onAfter
Updat
e
(
$event
)
{
$this
->
raiseEvent
(
'onAfter
Sav
e'
,
$event
);
$this
->
raiseEvent
(
'onAfter
Updat
e'
,
$event
);
}
/**
* This event is raised before the record is deleted.
* By setting
{@link ModelEvent::isValid} to be false, the normal {@link delete()}
process will be stopped.
* @param ModelEvent $event the event parameter
* By setting
[[\yii\base\ModelEvent::isValid]] to be false, the normal [[delete()]]
process will be stopped.
* @param
\yii\base\
ModelEvent $event the event parameter
*/
public
function
onBeforeDelete
(
$event
)
{
...
...
@@ -651,7 +855,7 @@ abstract class ActiveRecord extends Model
/**
* This event is raised after the record is deleted.
* @param Event $event the event parameter
* @param
\yii\base\
Event $event the event parameter
*/
public
function
onAfterDelete
(
$event
)
{
...
...
@@ -667,10 +871,37 @@ abstract class ActiveRecord extends Model
* Make sure you call the parent implementation so that the event is raised properly.
* @return boolean whether the saving should be executed. Defaults to true.
*/
public
function
beforeSave
()
public
function
beforeInsert
()
{
$event
=
new
ModelEvent
(
$this
);
$this
->
onBeforeInsert
(
$event
);
return
$event
->
isValid
;
}
/**
* This method is invoked after saving a record successfully.
* The default implementation raises the {@link onAfterSave} event.
* You may override this method to do postprocessing after record saving.
* Make sure you call the parent implementation so that the event is raised properly.
*/
public
function
afterInsert
()
{
$this
->
onAfterInsert
(
new
Event
(
$this
));
}
/**
* This method is invoked before saving a record (after validation, if any).
* The default implementation raises the {@link onBeforeSave} event.
* You may override this method to do any preparation work for record saving.
* Use {@link isNewRecord} to determine whether the saving is
* for inserting or updating record.
* Make sure you call the parent implementation so that the event is raised properly.
* @return boolean whether the saving should be executed. Defaults to true.
*/
public
function
beforeUpdate
()
{
$event
=
new
ModelEvent
(
$this
);
$this
->
onBefore
Sav
e
(
$event
);
$this
->
onBefore
Updat
e
(
$event
);
return
$event
->
isValid
;
}
...
...
@@ -680,9 +911,9 @@ abstract class ActiveRecord extends Model
* You may override this method to do postprocessing after record saving.
* Make sure you call the parent implementation so that the event is raised properly.
*/
public
function
after
Sav
e
()
public
function
after
Updat
e
()
{
$this
->
onAfter
Sav
e
(
new
Event
(
$this
));
$this
->
onAfter
Updat
e
(
new
Event
(
$this
));
}
/**
...
...
@@ -711,183 +942,31 @@ abstract class ActiveRecord extends Model
}
/**
* Inserts a row into the table based on this active record attributes.
* If the table's primary key is auto-incremental and is null before insertion,
* it will be populated with the actual value after insertion.
* Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
* After the record is inserted to DB successfully, its {@link isNewRecord} property will be set false,
* and its {@link scenario} property will be set to be 'update'.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the attributes are valid and the record is inserted successfully.
* @throws Exception if the record is not new
*/
public
function
insert
(
$attributes
=
null
)
{
if
(
$this
->
beforeSave
())
{
$db
=
$this
->
getDbConnection
();
$query
=
new
Query
;
$values
=
$this
->
getChangedAttributes
(
$attributes
);
$command
=
$query
->
insert
(
$this
->
tableName
(),
$values
)
->
createCommand
(
$db
);
if
(
$command
->
execute
())
{
$table
=
$this
->
getMetaData
()
->
table
;
if
(
$table
->
sequenceName
!==
null
)
{
foreach
(
$table
->
primaryKey
as
$name
)
{
if
(
$this
->
$name
===
null
)
{
$this
->
_attributes
[
$name
]
=
$db
->
getLastInsertID
(
$table
->
sequenceName
);
break
;
}
}
}
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
];
}
$this
->
afterSave
();
$this
->
setIsNewRecord
(
false
);
return
true
;
}
}
return
false
;
}
/**
* Updates the row represented by this active record.
* All loaded attributes will be saved to the database.
* Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the update is successful
* @throws Exception if the record is new
*/
public
function
update
(
$attributes
=
null
)
{
if
(
$this
->
beforeSave
())
{
$values
=
$this
->
getChangedAttributes
(
$attributes
);
if
(
$values
!==
array
())
{
$this
->
updateAll
(
$values
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
];
}
}
$this
->
afterSave
();
$this
->
setIsNewRecord
(
false
);
return
true
;
}
else
{
return
false
;
}
}
/**
* Saves a selected list of attributes.
* Unlike {@link save}, this method only saves the specified attributes
* of an existing row and does NOT call either {@link beforeSave} or {@link afterSave}.
* Also note that this method does not validate attributes.
* So do not use this method with untrusted data (such as user posted data).
* You may consider the following alternative if you want to do so:
*
* ~~~
* $user = User::find($id)->one;
* $user->attributes = $_POST['User'];
* $user->save();
* ~~~
*
* @param array $attributes attributes to be updated. Each element represents an attribute name
* or an attribute value indexed by its name. If the latter, the record's
* attribute will be changed accordingly before saving.
* @return boolean whether the update is successful
* @throws Exception if the record is new or any database error
*/
public
function
saveAttributes
(
$attributes
)
{
if
(
!
$this
->
getIsNewRecord
())
{
$values
=
array
();
foreach
(
$attributes
as
$name
=>
$value
)
{
if
(
is_integer
(
$name
))
{
$values
[
$value
]
=
$this
->
$value
;
}
else
{
$values
[
$name
]
=
$this
->
$name
=
$value
;
}
}
$this
->
updateAll
(
$values
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$value
;
}
return
true
;
}
else
{
throw
new
Exception
(
'The active record cannot be updated because it is new.'
);
}
}
/**
* Saves one or several counter columns for the current AR object.
* Note that this method differs from {@link updateCounters} in that it only
* saves the current AR object.
* An example usage is as follows:
* <pre>
* $postRecord=Post::model()->findByPk($postID);
* $postRecord->saveCounters(array('view_count'=>1));
* </pre>
* Use negative values if you want to decrease the counters.
* @param array $counters the counters to be updated (column name=>increment value)
* @return boolean whether the saving is successful
* @see updateCounters
*/
public
function
saveCounters
(
$counters
)
{
if
(
!
$this
->
getIsNewRecord
())
{
$this
->
updateCounters
(
$counters
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$counters
as
$name
=>
$value
)
{
$this
->
$name
+=
$value
;
$this
->
_oldAttributes
[
$name
]
=
$this
->
$name
;
}
return
true
;
}
else
{
throw
new
Exception
(
'The active record cannot be updated because it is new.'
);
}
}
/**
* Deletes the row corresponding to this active record.
* @return boolean whether the deletion is successful.
* @throws Exception if the record is new
*/
public
function
delete
()
{
if
(
!
$this
->
getIsNewRecord
())
{
if
(
$this
->
beforeDelete
())
{
$result
=
$this
->
deleteAll
(
$this
->
getPrimaryKey
(
true
))
>
0
;
$this
->
_oldAttributes
=
null
;
$this
->
afterDelete
();
return
$result
;
}
else
{
return
false
;
}
}
else
{
throw
new
Exception
(
'The active record cannot be deleted because it is new.'
);
}
}
/**
* Repopulates this active record with the latest data.
* @param array $attributes
* @return boolean whether the row still exists in the database. If true, the latest data will be populated to this active record.
*/
public
function
refresh
(
$attributes
=
null
)
{
if
(
!
$this
->
getIsNewRecord
()
&&
(
$record
=
$this
->
find
(
$this
->
getPrimaryKey
(
true
)))
!==
null
)
{
if
(
$attributes
===
null
)
{
$attributes
=
$this
->
attributeNames
();
if
(
$this
->
getIsNewRecord
())
{
return
false
;
}
$this
->
_attributes
=
array
();
foreach
(
$attributes
as
$name
)
{
$record
=
$this
->
find
()
->
where
(
$this
->
getPrimaryKey
(
true
))
->
one
();
if
(
$record
===
null
)
{
return
false
;
}
if
(
$attributes
===
null
)
{
foreach
(
$this
->
attributeNames
()
as
$name
)
{
$this
->
_attributes
[
$name
]
=
$record
->
_attributes
[
$name
];
}
$this
->
_oldAttributes
=
$this
->
_attributes
;
return
true
;
}
else
{
return
false
;
foreach
(
$attributes
as
$name
)
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
]
=
$record
->
_attributes
[
$name
];
}
}
return
true
;
}
/**
* Compares current active record with another one.
...
...
@@ -911,11 +990,11 @@ abstract class ActiveRecord extends Model
{
$table
=
static
::
getMetaData
()
->
table
;
if
(
count
(
$table
->
primaryKey
)
===
1
&&
!
$asArray
)
{
return
$this
->
{
$table
->
primaryKey
[
0
]}
;
return
isset
(
$this
->
_attributes
[
$table
->
primaryKey
[
0
]])
?
$this
->
_attributes
[
$table
->
primaryKey
[
0
]]
:
null
;
}
else
{
$values
=
array
();
foreach
(
$table
->
primaryKey
as
$name
)
{
$values
[
$name
]
=
$this
->
$name
;
$values
[
$name
]
=
isset
(
$this
->
_attributes
[
$name
])
?
$this
->
_attributes
[
$name
]
:
null
;
}
return
$values
;
}
...
...
@@ -928,7 +1007,8 @@ abstract class ActiveRecord extends Model
* The value remains unchanged even if the primary key attribute is manually assigned with a different value.
* @param boolean $asArray whether to return the primary key value as an array. If true,
* the return value will be an array with column name as key and column value as value.
* @return mixed the old primary key value. An array (column name=>column value) is returned if the primary key is composite.
* If this is false (default), a scalar value will be returned for non-composite primary key.
* @return string|array the old primary key value. An array (column name=>column value) is returned if the primary key is composite.
* If primary key is not defined, null will be returned.
*/
public
function
getOldPrimaryKey
(
$asArray
=
false
)
...
...
@@ -948,19 +1028,19 @@ abstract class ActiveRecord extends Model
/**
* Creates an active record with the given attributes.
* This method is internally used by the find methods.
*
* @param array $row attribute values (column name=>column value)
*
* @return ActiveRecord the newly created active record. The class of the object is the same as the model class.
* Null is returned if the input data is false.
*/
public
static
function
populateData
(
$row
)
public
static
function
createRecord
(
$row
)
{
$record
=
static
::
instantiate
(
$row
);
$columns
=
static
::
getMetaData
()
->
table
->
columns
;
foreach
(
$row
as
$name
=>
$value
)
{
if
(
isset
(
$columns
[
$name
]))
{
$record
->
_attributes
[
$name
]
=
$value
;
}
elseif
(
$record
->
canSetProperty
(
$name
))
{
$record
->
$name
=
$value
;
}
}
$record
->
_oldAttributes
=
$record
->
_attributes
;
...
...
@@ -969,7 +1049,7 @@ abstract class ActiveRecord extends Model
/**
* Creates an active record instance.
* This method is called by
{@link populateData}
.
* This method is called by
[[createRecord()]]
.
* You may override this method if the instance being created
* depends the attributes that are to be populated to the record.
* For example, by creating a record based on the value of a column,
...
...
framework/db/ar/ActiveRecordBehavior.php
View file @
965fe5c4
...
...
@@ -27,8 +27,10 @@ class CActiveRecordBehavior extends CModelBehavior
public
function
events
()
{
return
array_merge
(
parent
::
events
(),
array
(
'onBeforeSave'
=>
'beforeSave'
,
'onAfterSave'
=>
'afterSave'
,
'onBeforeInsert'
=>
'beforeInsert'
,
'onAfterInsert'
=>
'afterInsert'
,
'onBeforeUpdate'
=>
'beforeUpdate'
,
'onAfterUpdate'
=>
'afterUpdate'
,
'onBeforeDelete'
=>
'beforeDelete'
,
'onAfterDelete'
=>
'afterDelete'
,
'onBeforeFind'
=>
'beforeFind'
,
...
...
@@ -42,7 +44,7 @@ class CActiveRecordBehavior extends CModelBehavior
* You may set {@link CModelEvent::isValid} to be false to quit the saving process.
* @param CModelEvent $event event parameter
*/
public
function
before
Save
(
$event
)
public
function
before
Insert
(
$event
)
{
}
...
...
@@ -51,7 +53,26 @@ class CActiveRecordBehavior extends CModelBehavior
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CModelEvent $event event parameter
*/
public
function
afterSave
(
$event
)
public
function
afterInsert
(
$event
)
{
}
/**
* Responds to {@link CActiveRecord::onBeforeSave} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* You may set {@link CModelEvent::isValid} to be false to quit the saving process.
* @param CModelEvent $event event parameter
*/
public
function
beforeUpdate
(
$event
)
{
}
/**
* Responds to {@link CActiveRecord::onAfterSave} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CModelEvent $event event parameter
*/
public
function
afterUpdate
(
$event
)
{
}
...
...
framework/db/ar/ActiveRelation.php
View file @
965fe5c4
<?php
/**
* ActiveRelation class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\ar
;
class
ActiveRelation
extends
\yii\base\Object
use
yii\db\dao\BaseQuery
;
/**
* ActiveRelation represents the specification of a relation declared in [[ActiveRecord::relations()]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
ActiveRelation
extends
BaseQuery
{
/**
* @var string the name of this relation
*/
public
$name
;
public
$modelClass
;
public
$hasMany
;
public
$joinType
;
public
$tableAlias
;
public
$on
;
public
$via
;
public
$with
;
public
$scopes
;
/**
* @var string|array the columns being selected. This refers to the SELECT clause in a SQL
* statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`).
* If not set, if means all columns.
* @see select()
* @var string the name of the model class that this relation represents
*/
public
$
select
;
public
$
modelClass
;
/**
* @var string|array query condition. This refers to the WHERE clause in a SQL statement.
* For example, `age > 31 AND team = 1`.
* @see where()
* @var boolean whether this relation is a one-many relation
*/
public
$
where
;
public
$
hasMany
;
/**
* @var
integer maximum number of records to be returned. If not set or less than 0, it means no limit
.
* @var
string the join type (e.g. INNER JOIN, LEFT JOIN). Defaults to 'LEFT JOIN'
.
*/
public
$
limit
;
public
$
joinType
=
'LEFT JOIN'
;
/**
* @var integer zero-based offset from where the records are to be returned. If not set or
* less than 0, it means starting from the beginning.
* @var string the table alias used for the corresponding table during query
*/
public
$
offset
;
public
$
tableAlias
;
/**
* @var string
|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement
.
*
It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`)
.
* @var string
the name of the column that the result should be indexed by
.
*
This is only useful when [[hasMany]] is true
.
*/
public
$
order
By
;
public
$
index
By
;
/**
* @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement.
* It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`).
* @var string the ON clause of the join query
*/
public
$
groupBy
;
public
$
on
;
/**
* @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement.
* It can either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g.
* `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`).
* @see join()
* @var string
*/
public
$
join
;
public
$
via
;
/**
* @var string|array the condition to be applied in the GROUP BY clause.
* It can be either a string or an array. Please refer to [[where()]] on how to specify the condition.
* @var array the relations that should be queried together (eager loading)
*/
public
$
having
;
public
$
with
;
/**
* @var array list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* @var array the scopes that should be applied during query
*/
public
$
param
s
;
public
$
scope
s
;
}
framework/db/dao/BaseQuery.php
0 → 100644
View file @
965fe5c4
<?php
/**
* BaseQuery class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\dao
;
/**
* BaseQuery is the base class that represents a SQL SELECT statement in a DBMS-independent way.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
BaseQuery
extends
\yii\base\Object
{
/**
* @var string|array the columns being selected. This refers to the SELECT clause in a SQL
* statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`).
* If not set, if means all columns.
* @see select()
*/
public
$select
;
/**
* @var string additional option that should be appended to the 'SELECT' keyword. For example,
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
*/
public
$selectOption
;
/**
* @var boolean whether to select distinct rows of data only. If this is set true,
* the SELECT clause would be changed to SELECT DISTINCT.
*/
public
$distinct
;
/**
* @var string|array the table(s) to be selected from. This refers to the FROM clause in a SQL statement.
* It can be either a string (e.g. `'tbl_user, tbl_post'`) or an array (e.g. `array('tbl_user', 'tbl_post')`).
* @see from()
*/
public
$from
;
/**
* @var string|array query condition. This refers to the WHERE clause in a SQL statement.
* For example, `age > 31 AND team = 1`.
* @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 or
* less than 0, it means starting from the beginning.
*/
public
$offset
;
/**
* @var string|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement.
* It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`).
*/
public
$orderBy
;
/**
* @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement.
* It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`).
*/
public
$groupBy
;
/**
* @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement.
* It can either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g.
* `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`).
* @see join()
*/
public
$join
;
/**
* @var string|array the condition to be applied in the GROUP BY clause.
* It can be either a string or an array. Please refer to [[where()]] on how to specify the condition.
*/
public
$having
;
/**
* @var array list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
*/
public
$params
;
/**
* @var string|BaseQuery[] the UNION clause(s) in a SQL statement. This can be either a string
* representing a single UNION clause or an array representing multiple UNION clauses.
* Each union clause can be a string or a `BaseQuery` object which refers to the SQL statement.
*/
public
$union
;
/**
* Sets the SELECT part of the query.
* @param string|array $columns the columns to be selected.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* Columns can contain table prefixes (e.g. "tbl_user.id") and/or column aliases (e.g. "tbl_user.id AS user_id").
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @param string $option additional option that should be appended to the 'SELECT' keyword. For example,
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
* @return BaseQuery the query object itself
*/
public
function
select
(
$columns
,
$option
=
null
)
{
$this
->
select
=
$columns
;
$this
->
selectOption
=
$option
;
return
$this
;
}
/**
* Sets the value indicating whether to SELECT DISTINCT or not.
* @param bool $value whether to SELECT DISTINCT or not.
* @return BaseQuery the query object itself
*/
public
function
distinct
(
$value
=
true
)
{
$this
->
distinct
=
$value
;
return
$this
;
}
/**
* Sets the FROM part of the query.
* @param string|array $tables the table(s) to be selected from. This can be either a string (e.g. `'tbl_user'`)
* or an array (e.g. `array('tbl_user', 'tbl_profile')`) specifying one or several table names.
* Table names can contain schema prefixes (e.g. `'public.tbl_user'`) and/or table aliases (e.g. `'tbl_user u'`).
* The method will automatically quote the table names unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @return BaseQuery the query object itself
*/
public
function
from
(
$tables
)
{
$this
->
from
=
$tables
;
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.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
* @see andWhere()
* @see orWhere()
*/
public
function
where
(
$condition
,
$params
=
array
())
{
$this
->
where
=
$condition
;
$this
->
addParams
(
$params
);
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.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
* @see where()
* @see orWhere()
*/
public
function
andWhere
(
$condition
,
$params
=
array
())
{
if
(
$this
->
where
===
null
)
{
$this
->
where
=
$condition
;
}
else
{
$this
->
where
=
array
(
'and'
,
$this
->
where
,
$condition
);
}
$this
->
addParams
(
$params
);
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.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
* @see where()
* @see andWhere()
*/
public
function
orWhere
(
$condition
,
$params
=
array
())
{
if
(
$this
->
where
===
null
)
{
$this
->
where
=
$condition
;
}
else
{
$this
->
where
=
array
(
'or'
,
$this
->
where
,
$condition
);
}
$this
->
addParams
(
$params
);
return
$this
;
}
/**
* Appends a JOIN part to the query.
* The first parameter specifies what type of join it is.
* @param string $type the type of join, such as INNER JOIN, LEFT JOIN.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
*/
public
function
join
(
$type
,
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
$type
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Appends an INNER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
*/
public
function
innerJoin
(
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
'INNER JOIN'
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Appends a LEFT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return BaseQuery the query object itself
*/
public
function
leftJoin
(
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
'LEFT JOIN'
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Appends a RIGHT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return BaseQuery the query object itself
*/
public
function
rightJoin
(
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
'RIGHT JOIN'
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Sets the GROUP BY part of the query.
* @param string|array $columns the columns to be grouped by.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return BaseQuery the query object itself
* @see addGroupBy()
*/
public
function
groupBy
(
$columns
)
{
$this
->
groupBy
=
$columns
;
return
$this
;
}
/**
* Adds additional group-by columns to the existing ones.
* @param string|array $columns additional columns to be grouped by.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return BaseQuery the query object itself
* @see groupBy()
*/
public
function
addGroupBy
(
$columns
)
{
if
(
empty
(
$this
->
groupBy
))
{
$this
->
groupBy
=
$columns
;
}
else
{
if
(
!
is_array
(
$this
->
groupBy
))
{
$this
->
groupBy
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$this
->
groupBy
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
if
(
!
is_array
(
$columns
))
{
$columns
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$columns
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
$this
->
groupBy
=
array_merge
(
$this
->
groupBy
,
$columns
);
}
return
$this
;
}
/**
* Sets the HAVING part of the query.
* @param string|array $condition the conditions to be put after HAVING.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
* @see andHaving()
* @see orHaving()
*/
public
function
having
(
$condition
,
$params
=
array
())
{
$this
->
having
=
$condition
;
$this
->
addParams
(
$params
);
return
$this
;
}
/**
* Adds an additional HAVING 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 HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
* @see having()
* @see orHaving()
*/
public
function
andHaving
(
$condition
,
$params
=
array
())
{
if
(
$this
->
having
===
null
)
{
$this
->
having
=
$condition
;
}
else
{
$this
->
having
=
array
(
'and'
,
$this
->
having
,
$condition
);
}
$this
->
addParams
(
$params
);
return
$this
;
}
/**
* Adds an additional HAVING 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 HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return BaseQuery the query object itself
* @see having()
* @see andHaving()
*/
public
function
orHaving
(
$condition
,
$params
=
array
())
{
if
(
$this
->
having
===
null
)
{
$this
->
having
=
$condition
;
}
else
{
$this
->
having
=
array
(
'or'
,
$this
->
having
,
$condition
);
}
$this
->
addParams
(
$params
);
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 ASC', 'name DESC')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return BaseQuery the query object itself
* @see addOrderBy()
*/
public
function
orderBy
(
$columns
)
{
$this
->
orderBy
=
$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 ASC', 'name DESC')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return BaseQuery the query object itself
* @see orderBy()
*/
public
function
addOrderBy
(
$columns
)
{
if
(
empty
(
$this
->
orderBy
))
{
$this
->
orderBy
=
$columns
;
}
else
{
if
(
!
is_array
(
$this
->
orderBy
))
{
$this
->
orderBy
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$this
->
orderBy
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
if
(
!
is_array
(
$columns
))
{
$columns
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$columns
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
$this
->
orderBy
=
array_merge
(
$this
->
orderBy
,
$columns
);
}
return
$this
;
}
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit
* @return BaseQuery 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 BaseQuery the query object itself
*/
public
function
offset
(
$offset
)
{
$this
->
offset
=
$offset
;
return
$this
;
}
/**
* Appends a SQL statement using UNION operator.
* @param string|BaseQuery $sql the SQL statement to be appended using UNION
* @return BaseQuery the query object itself
*/
public
function
union
(
$sql
)
{
$this
->
union
[]
=
$sql
;
return
$this
;
}
/**
* Sets the parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* @return BaseQuery the query object itself
* @see addParams()
*/
public
function
params
(
$params
)
{
$this
->
params
=
$params
;
return
$this
;
}
/**
* Adds additional parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* @return BaseQuery the query object itself
* @see params()
*/
public
function
addParams
(
$params
)
{
if
(
$params
!==
array
())
{
if
(
$this
->
params
===
null
)
{
$this
->
params
=
$params
;
}
else
{
foreach
(
$params
as
$name
=>
$value
)
{
if
(
is_integer
(
$name
))
{
$this
->
params
[]
=
$value
;
}
else
{
$this
->
params
[
$name
]
=
$value
;
}
}
}
}
return
$this
;
}
/**
* Merges this query with another one.
*
* The merging is done according to the following rules:
*
* - [[select]]: the union of both queries' [[select]] property values.
* - [[selectOption]], [[distinct]], [[from]], [[limit]], [[offset]]: the new query
* takes precedence over this query.
* - [[where]], [[having]]: the new query's corresponding property value
* will be 'AND' together with the existing one.
* - [[params]], [[orderBy]], [[groupBy]], [[join]], [[union]]: the new query's
* corresponding property value will be appended to the existing one.
*
* In general, the merging makes the resulting query more restrictive and specific.
* @param BaseQuery $query the new query to be merged with this query.
* @return BaseQuery the query object itself
*/
public
function
mergeWith
(
$query
)
{
if
(
$this
->
select
!==
$query
->
select
)
{
if
(
empty
(
$this
->
select
))
{
$this
->
select
=
$query
->
select
;
}
elseif
(
!
empty
(
$query
->
select
))
{
$select1
=
is_string
(
$this
->
select
)
?
preg_split
(
'/\s*,\s*/'
,
trim
(
$this
->
select
),
-
1
,
PREG_SPLIT_NO_EMPTY
)
:
$this
->
select
;
$select2
=
is_string
(
$query
->
select
)
?
preg_split
(
'/\s*,\s*/'
,
trim
(
$query
->
select
),
-
1
,
PREG_SPLIT_NO_EMPTY
)
:
$query
->
select
;
$this
->
select
=
array_merge
(
$select1
,
array_diff
(
$select2
,
$select1
));
}
}
if
(
$query
->
selectOption
!==
null
)
{
$this
->
selectOption
=
$query
->
selectOption
;
}
if
(
$query
->
distinct
!==
null
)
{
$this
->
distinct
=
$query
->
distinct
;
}
if
(
$query
->
from
!==
null
)
{
$this
->
from
=
$query
->
from
;
}
if
(
$query
->
limit
!==
null
)
{
$this
->
limit
=
$query
->
limit
;
}
if
(
$query
->
offset
!==
null
)
{
$this
->
offset
=
$query
->
offset
;
}
if
(
$query
->
where
!==
null
)
{
$this
->
andWhere
(
$query
->
where
);
}
if
(
$query
->
having
!==
null
)
{
$this
->
andHaving
(
$query
->
having
);
}
if
(
$query
->
params
!==
null
)
{
$this
->
addParams
(
$query
->
params
);
}
if
(
$query
->
orderBy
!==
null
)
{
$this
->
addOrderBy
(
$query
->
orderBy
);
}
if
(
$query
->
groupBy
!==
null
)
{
$this
->
addGroupBy
(
$query
->
groupBy
);
}
if
(
$query
->
join
!==
null
)
{
if
(
empty
(
$this
->
join
))
{
$this
->
join
=
$query
->
join
;
}
else
{
if
(
!
is_array
(
$this
->
join
))
{
$this
->
join
=
array
(
$this
->
join
);
}
if
(
is_array
(
$query
->
join
))
{
$this
->
join
=
array_merge
(
$this
->
join
,
$query
->
join
);
}
else
{
$this
->
join
[]
=
$query
->
join
;
}
}
}
if
(
$query
->
union
!==
null
)
{
if
(
empty
(
$this
->
union
))
{
$this
->
union
=
$query
->
union
;
}
else
{
if
(
!
is_array
(
$this
->
union
))
{
$this
->
union
=
array
(
$this
->
union
);
}
if
(
is_array
(
$query
->
union
))
{
$this
->
union
=
array_merge
(
$this
->
union
,
$query
->
union
);
}
else
{
$this
->
union
[]
=
$query
->
union
;
}
}
}
return
$this
;
}
}
framework/db/dao/Command.php
View file @
965fe5c4
...
...
@@ -64,27 +64,15 @@ class Command extends \yii\base\Component
/**
* Constructor.
* Instead of using the `new` operator, you may use [[Connection::createCommand()]]
* to create a new Command object.
* @param Connection $connection the database connection
* @param string|array|Query $query the DB query to be executed. This can be:
*
* - a string representing the SQL statement to be executed
* - a [[Query]] object representing the SQL query
* - an array that will be used to create and initialize the [[Query]] object
* @param string $sql the SQL statement to be executed
* @param array $params the parameters to be bound to the SQL statement
*/
public
function
__construct
(
$connection
,
$
query
=
null
)
public
function
__construct
(
$connection
,
$
sql
=
null
,
$params
=
array
()
)
{
$this
->
connection
=
$connection
;
if
(
is_array
(
$query
))
{
$query
=
Query
::
newInstance
(
$query
);
}
if
(
$query
instanceof
Query
)
{
$this
->
_sql
=
$query
->
getSql
(
$connection
);
$this
->
bindValues
(
$query
->
params
);
}
else
{
$this
->
_sql
=
$query
;
}
$this
->
_sql
=
$sql
;
$this
->
bindValues
(
$params
);
}
/**
...
...
@@ -233,8 +221,6 @@ class Command extends \yii\base\Component
$paramLog
=
"
\n
Parameters: "
.
var_export
(
$this
->
_params
,
true
);
}
echo
"Executing SQL:
{
$sql
}{
$paramLog
}
"
.
"
\n\n
"
;
\Yii
::
trace
(
"Executing SQL:
{
$sql
}{
$paramLog
}
"
,
__CLASS__
);
try
{
...
...
@@ -368,8 +354,6 @@ echo "Executing SQL: {$sql}{$paramLog}" . "\n\n";
$paramLog
=
"
\n
Parameters: "
.
var_export
(
$this
->
_params
,
true
);
}
echo
"Executing SQL:
{
$sql
}{
$paramLog
}
"
.
"
\n\n
"
;
\Yii
::
trace
(
"Querying SQL:
{
$sql
}{
$paramLog
}
"
,
__CLASS__
);
if
(
$db
->
queryCachingCount
>
0
&&
$db
->
queryCachingDuration
>=
0
&&
$method
!==
''
)
{
...
...
framework/db/dao/Connection.php
View file @
965fe5c4
...
...
@@ -399,17 +399,14 @@ class Connection extends \yii\base\ApplicationComponent
/**
* Creates a command for execution.
* @param string|array|Query $query the DB query to be executed. This can be:
*
* - a string representing the SQL statement to be executed
* - a [[Query]] object representing the SQL query
* - an array that will be used to initialize [[Query]]
* @param string $sql the SQL statement to be executed
* @param array $params the parameters to be bound to the SQL statement
* @return Command the DB command
*/
public
function
createCommand
(
$
query
=
null
)
public
function
createCommand
(
$
sql
=
null
,
$params
=
array
()
)
{
$this
->
open
();
return
new
Command
(
$this
,
$
query
);
return
new
Command
(
$this
,
$
sql
,
$params
);
}
/**
...
...
framework/db/dao/Query.php
View file @
965fe5c4
...
...
@@ -39,7 +39,7 @@ namespace yii\db\dao;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
Query
extends
\yii\base\Object
class
Query
extends
BaseQuery
{
/**
* @var array the operation that this query represents. This refers to the method call as well as
...
...
@@ -48,80 +48,11 @@ class Query extends \yii\base\Object
* If this property is not set, it means this query represents a SELECT statement.
*/
public
$operation
;
/**
* @var string|array the columns being selected. This refers to the SELECT clause in a SQL
* statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`).
* If not set, if means all columns.
* @see select()
*/
public
$select
;
/**
* @var string additional option that should be appended to the 'SELECT' keyword. For example,
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
*/
public
$selectOption
;
/**
* @var boolean whether to select distinct rows of data only. If this is set true,
* the SELECT clause would be changed to SELECT DISTINCT.
*/
public
$distinct
;
/**
* @var string|array the table(s) to be selected from. This refers to the FROM clause in a SQL statement.
* It can be either a string (e.g. `'tbl_user, tbl_post'`) or an array (e.g. `array('tbl_user', 'tbl_post')`).
* @see from()
*/
public
$from
;
/**
* @var string|array query condition. This refers to the WHERE clause in a SQL statement.
* For example, `age > 31 AND team = 1`.
* @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 or
* less than 0, it means starting from the beginning.
*/
public
$offset
;
/**
* @var string|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement.
* It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`).
*/
public
$orderBy
;
/**
* @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement.
* It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`).
*/
public
$groupBy
;
/**
* @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement.
* It can either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g.
* `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`).
* @see join()
*/
public
$join
;
/**
* @var string|array the condition to be applied in the GROUP BY clause.
* It can be either a string or an array. Please refer to [[where()]] on how to specify the condition.
*/
public
$having
;
/**
* @var array list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
*/
public
$params
;
/**
* @var string|Query[] the UNION clause(s) in a SQL statement. This can be either a string
* representing a single UNION clause or an array representing multiple UNION clauses.
* Each union clause can be a string or a `Query` object which refers to the SQL statement.
*/
public
$union
;
/**
* Generates and returns the SQL statement according to this query.
* Note that after calling this method, [[params]] may be modified with additional
* parameters generated by the query builder.
* @param Connection $connection the database connection used to generate the SQL statement.
* If this parameter is not given, the `db` application component will be used.
* @return string the generated SQL statement
...
...
@@ -131,7 +62,15 @@ class Query extends \yii\base\Object
if
(
$connection
===
null
)
{
$connection
=
\Yii
::
$application
->
db
;
}
return
$connection
->
getQueryBuilder
()
->
build
(
$this
);
$qb
=
$connection
->
getQueryBuilder
();
if
(
$this
->
operation
!==
null
)
{
$params
=
$this
->
operation
;
$method
=
array_shift
(
$params
);
$qb
->
query
=
$this
;
return
call_user_func_array
(
array
(
$qb
,
$method
),
$params
);
}
else
{
return
$qb
->
build
(
$this
);
}
}
/**
...
...
@@ -145,7 +84,8 @@ class Query extends \yii\base\Object
if
(
$connection
===
null
)
{
$connection
=
\Yii
::
$application
->
db
;
}
return
$connection
->
createCommand
(
$this
);
$sql
=
$this
->
getSql
(
$connection
);
return
$connection
->
createCommand
(
$sql
,
$this
->
params
);
}
/**
...
...
@@ -157,7 +97,7 @@ class Query extends \yii\base\Object
*/
public
function
insert
(
$table
,
$columns
)
{
$this
->
operation
=
array
(
__FUNCTION__
,
$table
,
$columns
,
array
()
);
$this
->
operation
=
array
(
__FUNCTION__
,
$table
,
$columns
);
return
$this
;
}
...
...
@@ -173,8 +113,7 @@ class Query extends \yii\base\Object
*/
public
function
update
(
$table
,
$columns
,
$condition
=
''
,
$params
=
array
())
{
$this
->
addParams
(
$params
);
$this
->
operation
=
array
(
__FUNCTION__
,
$table
,
$columns
,
$condition
,
array
());
$this
->
operation
=
array
(
__FUNCTION__
,
$table
,
$columns
,
$condition
,
$params
);
return
$this
;
}
...
...
@@ -188,8 +127,8 @@ class Query extends \yii\base\Object
*/
public
function
delete
(
$table
,
$condition
=
''
,
$params
=
array
())
{
$this
->
operation
=
array
(
__FUNCTION__
,
$table
,
$condition
);
return
$this
->
addParams
(
$params
)
;
$this
->
operation
=
array
(
__FUNCTION__
,
$table
,
$condition
,
$params
);
return
$this
;
}
/**
...
...
@@ -361,559 +300,4 @@ class Query extends \yii\base\Object
$this
->
operation
=
array
(
__FUNCTION__
,
$name
,
$table
);
return
$this
;
}
/**
* Sets the SELECT part of the query.
* @param string|array $columns the columns to be selected.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* Columns can contain table prefixes (e.g. "tbl_user.id") and/or column aliases (e.g. "tbl_user.id AS user_id").
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @param string $option additional option that should be appended to the 'SELECT' keyword. For example,
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
* @return Query the query object itself
*/
public
function
select
(
$columns
,
$option
=
''
)
{
$this
->
select
=
$columns
;
$this
->
selectOption
=
$option
;
return
$this
;
}
/**
* Sets the value indicating whether to SELECT DISTINCT or not.
* @param bool $value whether to SELECT DISTINCT or not.
* @return Query the query object itself
*/
public
function
distinct
(
$value
=
true
)
{
$this
->
distinct
=
$value
;
return
$this
;
}
/**
* Sets the FROM part of the query.
* @param string|array $tables the table(s) to be selected from. This can be either a string (e.g. 'tbl_user')
* or an array (e.g. array('tbl_user', 'tbl_profile')) specifying one or several table names.
* Table names can contain schema prefixes (e.g. 'public.tbl_user') and/or table aliases (e.g. 'tbl_user u').
* The method will automatically quote the table names unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @return Query the query object itself
*/
public
function
from
(
$tables
)
{
$this
->
from
=
$tables
;
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.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
* @see andWhere()
* @see orWhere()
*/
public
function
where
(
$condition
,
$params
=
array
())
{
$this
->
where
=
$condition
;
$this
->
addParams
(
$params
);
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.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
* @see where()
* @see orWhere()
*/
public
function
andWhere
(
$condition
,
$params
=
array
())
{
if
(
$this
->
where
===
null
)
{
$this
->
where
=
$condition
;
}
else
{
$this
->
where
=
array
(
'and'
,
$this
->
where
,
$condition
);
}
$this
->
addParams
(
$params
);
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.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
* @see where()
* @see andWhere()
*/
public
function
orWhere
(
$condition
,
$params
=
array
())
{
if
(
$this
->
where
===
null
)
{
$this
->
where
=
$condition
;
}
else
{
$this
->
where
=
array
(
'or'
,
$this
->
where
,
$condition
);
}
$this
->
addParams
(
$params
);
return
$this
;
}
/**
* Appends a JOIN part to the query.
* The first parameter specifies what type of join it is.
* @param string $type the type of join, such as INNER JOIN, LEFT JOIN.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
*/
public
function
join
(
$type
,
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
$type
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Appends an INNER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
*/
public
function
innerJoin
(
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
'INNER JOIN'
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Appends a LEFT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Query the query object itself
*/
public
function
leftJoin
(
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
'LEFT JOIN'
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Appends a RIGHT OUTER JOIN part to the query.
* @param string $table the table to be joined.
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u').
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param string|array $on the join condition that should appear in the ON part.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Query the query object itself
*/
public
function
rightJoin
(
$table
,
$on
=
''
,
$params
=
array
())
{
$this
->
join
[]
=
array
(
'RIGHT JOIN'
,
$table
,
$on
);
return
$this
->
addParams
(
$params
);
}
/**
* Sets the GROUP BY part of the query.
* @param string|array $columns the columns to be grouped by.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see addGroupBy()
*/
public
function
groupBy
(
$columns
)
{
$this
->
groupBy
=
$columns
;
return
$this
;
}
/**
* Adds additional group-by columns to the existing ones.
* @param string|array $columns additional columns to be grouped by.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see groupBy()
*/
public
function
addGroupBy
(
$columns
)
{
if
(
empty
(
$this
->
groupBy
))
{
$this
->
groupBy
=
$columns
;
}
else
{
if
(
!
is_array
(
$this
->
groupBy
))
{
$this
->
groupBy
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$this
->
groupBy
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
if
(
!
is_array
(
$columns
))
{
$columns
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$columns
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
$this
->
groupBy
=
array_merge
(
$this
->
groupBy
,
$columns
);
}
return
$this
;
}
/**
* Sets the HAVING part of the query.
* @param string|array $condition the conditions to be put after HAVING.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
* @see andHaving()
* @see orHaving()
*/
public
function
having
(
$condition
,
$params
=
array
())
{
$this
->
having
=
$condition
;
$this
->
addParams
(
$params
);
return
$this
;
}
/**
* Adds an additional HAVING 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 HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
* @see having()
* @see orHaving()
*/
public
function
andHaving
(
$condition
,
$params
=
array
())
{
if
(
$this
->
having
===
null
)
{
$this
->
having
=
$condition
;
}
else
{
$this
->
having
=
array
(
'and'
,
$this
->
having
,
$condition
);
}
$this
->
addParams
(
$params
);
return
$this
;
}
/**
* Adds an additional HAVING 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 HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return Query the query object itself
* @see having()
* @see andHaving()
*/
public
function
orHaving
(
$condition
,
$params
=
array
())
{
if
(
$this
->
having
===
null
)
{
$this
->
having
=
$condition
;
}
else
{
$this
->
having
=
array
(
'or'
,
$this
->
having
,
$condition
);
}
$this
->
addParams
(
$params
);
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 ASC', 'name DESC')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see addOrderBy()
*/
public
function
orderBy
(
$columns
)
{
$this
->
orderBy
=
$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 ASC', 'name DESC')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see orderBy()
*/
public
function
addOrderBy
(
$columns
)
{
if
(
empty
(
$this
->
orderBy
))
{
$this
->
orderBy
=
$columns
;
}
else
{
if
(
!
is_array
(
$this
->
orderBy
))
{
$this
->
orderBy
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$this
->
orderBy
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
if
(
!
is_array
(
$columns
))
{
$columns
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$columns
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
$this
->
orderBy
=
array_merge
(
$this
->
orderBy
,
$columns
);
}
return
$this
;
}
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit
* @return Query 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 Query the query object itself
*/
public
function
offset
(
$offset
)
{
$this
->
offset
=
$offset
;
return
$this
;
}
/**
* Appends a SQL statement using UNION operator.
* @param string|Query $sql the SQL statement to be appended using UNION
* @return Query the query object itself
*/
public
function
union
(
$sql
)
{
$this
->
union
[]
=
$sql
;
return
$this
;
}
/**
* Sets the parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* @return Query the query object itself
* @see addParams()
*/
public
function
params
(
$params
)
{
$this
->
params
=
$params
;
return
$this
;
}
/**
* Adds additional parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* @return Query the query object itself
* @see params()
*/
public
function
addParams
(
$params
)
{
if
(
$params
!==
array
())
{
if
(
$this
->
params
===
null
)
{
$this
->
params
=
$params
;
}
else
{
foreach
(
$params
as
$name
=>
$value
)
{
if
(
is_integer
(
$name
))
{
$this
->
params
[]
=
$value
;
}
else
{
$this
->
params
[
$name
]
=
$value
;
}
}
}
}
return
$this
;
}
/**
* Merges this query with another one.
*
* The merging is done according to the following rules:
*
* - [[select]]: the union of both queries' [[select]] property values.
* - [[selectOption]], [[distinct]], [[from]], [[limit]], [[offset]]: the new query
* takes precedence over this query.
* - [[where]], [[having]]: the new query's corresponding property value
* will be 'AND' together with the existing one.
* - [[params]], [[orderBy]], [[groupBy]], [[join]], [[union]]: the new query's
* corresponding property value will be appended to the existing one.
*
* In general, the merging makes the resulting query more restrictive and specific.
* @param Query $query the new query to be merged with this query.
* @return Query the query object itself
*/
public
function
mergeWith
(
$query
)
{
if
(
$this
->
select
!==
$query
->
select
)
{
if
(
empty
(
$this
->
select
))
{
$this
->
select
=
$query
->
select
;
}
elseif
(
!
empty
(
$query
->
select
))
{
$select1
=
is_string
(
$this
->
select
)
?
preg_split
(
'/\s*,\s*/'
,
trim
(
$this
->
select
),
-
1
,
PREG_SPLIT_NO_EMPTY
)
:
$this
->
select
;
$select2
=
is_string
(
$query
->
select
)
?
preg_split
(
'/\s*,\s*/'
,
trim
(
$query
->
select
),
-
1
,
PREG_SPLIT_NO_EMPTY
)
:
$query
->
select
;
$this
->
select
=
array_merge
(
$select1
,
array_diff
(
$select2
,
$select1
));
}
}
if
(
$query
->
selectOption
!==
null
)
{
$this
->
selectOption
=
$query
->
selectOption
;
}
if
(
$query
->
distinct
!==
null
)
{
$this
->
distinct
=
$query
->
distinct
;
}
if
(
$query
->
from
!==
null
)
{
$this
->
from
=
$query
->
from
;
}
if
(
$query
->
limit
!==
null
)
{
$this
->
limit
=
$query
->
limit
;
}
if
(
$query
->
offset
!==
null
)
{
$this
->
offset
=
$query
->
offset
;
}
if
(
$query
->
where
!==
null
)
{
$this
->
andWhere
(
$query
->
where
);
}
if
(
$query
->
having
!==
null
)
{
$this
->
andHaving
(
$query
->
having
);
}
if
(
$query
->
params
!==
null
)
{
$this
->
addParams
(
$query
->
params
);
}
if
(
$query
->
orderBy
!==
null
)
{
$this
->
addOrderBy
(
$query
->
orderBy
);
}
if
(
$query
->
groupBy
!==
null
)
{
$this
->
addGroupBy
(
$query
->
groupBy
);
}
if
(
$query
->
join
!==
null
)
{
if
(
empty
(
$this
->
join
))
{
$this
->
join
=
$query
->
join
;
}
else
{
if
(
!
is_array
(
$this
->
join
))
{
$this
->
join
=
array
(
$this
->
join
);
}
if
(
is_array
(
$query
->
join
))
{
$this
->
join
=
array_merge
(
$this
->
join
,
$query
->
join
);
}
else
{
$this
->
join
[]
=
$query
->
join
;
}
}
}
if
(
$query
->
union
!==
null
)
{
if
(
empty
(
$this
->
union
))
{
$this
->
union
=
$query
->
union
;
}
else
{
if
(
!
is_array
(
$this
->
union
))
{
$this
->
union
=
array
(
$this
->
union
);
}
if
(
is_array
(
$query
->
union
))
{
$this
->
union
=
array_merge
(
$this
->
union
,
$query
->
union
);
}
else
{
$this
->
union
[]
=
$query
->
union
;
}
}
}
return
$this
;
}
/**
* Resets the query object to its original state.
* @return Query the query object itself
*/
public
function
reset
()
{
foreach
(
get_object_vars
(
$this
)
as
$name
=>
$value
)
{
$this
->
$name
=
null
;
}
return
$this
;
}
}
framework/db/dao/QueryBuilder.php
View file @
965fe5c4
...
...
@@ -13,9 +13,9 @@ namespace yii\db\dao;
use
yii\db\Exception
;
/**
* QueryBuilder builds a S
QL statement based on the specification given as a [[
Query]] object.
* QueryBuilder builds a S
ELECT SQL statement based on the specification given as a [[Base
Query]] object.
*
* QueryBuilder
is often used behind the scenes by [[Query]] to build a DBMS-dependent SQL statement
* QueryBuilder
can also be used to build SQL statements such as INSERT, UPDATE, DELETE, CREATE TABLE,
* from a [[Query]] object.
*
* @author Qiang Xue <qiang.xue@gmail.com>
...
...
@@ -57,22 +57,13 @@ class QueryBuilder extends \yii\base\Object
}
/**
* Generates a SQL statement from a [[Query]] object.
* Note that when generating SQL statements for INSERT and UPDATE queries,
* the query object's [[Query::params]] property may be appended with new parameters.
* @param Query $query the [[Query]] object from which the SQL statement will be generated
* Generates a SELECT SQL statement from a [[BaseQuery]] object.
* @param BaseQuery $query the [[Query]] object from which the SQL statement will be generated
* @return string the generated SQL statement
*/
public
function
build
(
$query
)
{
$this
->
query
=
$query
;
if
(
$query
->
operation
!==
null
)
{
// non-SELECT query
$params
=
$query
->
operation
;
$method
=
array_shift
(
$params
);
return
call_user_func_array
(
array
(
$this
,
$method
),
$params
);
}
else
{
// SELECT query
$clauses
=
array
(
$this
->
buildSelect
(),
$this
->
buildFrom
(),
...
...
@@ -86,7 +77,6 @@ class QueryBuilder extends \yii\base\Object
);
return
implode
(
$this
->
separator
,
array_filter
(
$clauses
));
}
}
/**
* Creates and executes an INSERT SQL statement.
...
...
@@ -123,7 +113,7 @@ class QueryBuilder extends \yii\base\Object
$count
++
;
}
}
if
(
$this
->
query
instanceof
Query
)
{
if
(
$this
->
query
instanceof
Base
Query
)
{
$this
->
query
->
addParams
(
$params
);
}
...
...
@@ -167,7 +157,7 @@ class QueryBuilder extends \yii\base\Object
$count
++
;
}
}
if
(
$this
->
query
instanceof
Query
)
{
if
(
$this
->
query
instanceof
Base
Query
)
{
$this
->
query
->
addParams
(
$params
);
}
$sql
=
'UPDATE '
.
$this
->
quoteTableName
(
$table
)
.
' SET '
.
implode
(
', '
,
$lines
);
...
...
@@ -189,14 +179,18 @@ class QueryBuilder extends \yii\base\Object
* @param string $table the table where the data will be deleted from.
* @param mixed $condition the condition that will be put in the WHERE part. Please
* refer to [[Query::where()]] on how to specify condition.
* @param array $params the parameters to be bound to the query.
* @return integer number of rows affected by the execution.
*/
public
function
delete
(
$table
,
$condition
=
''
)
public
function
delete
(
$table
,
$condition
=
''
,
$params
=
array
()
)
{
$sql
=
'DELETE FROM '
.
$this
->
quoteTableName
(
$table
);
if
((
$where
=
$this
->
buildCondition
(
$condition
))
!=
''
)
{
$sql
.=
' WHERE '
.
$where
;
}
if
(
$params
!==
array
()
&&
$this
->
query
instanceof
BaseQuery
)
{
$this
->
query
->
addParams
(
$params
);
}
return
$sql
;
}
...
...
@@ -631,7 +625,7 @@ class QueryBuilder extends \yii\base\Object
protected
function
buildSelect
()
{
$select
=
$this
->
query
->
distinct
?
'SELECT DISTINCT'
:
'SELECT'
;
if
(
$this
->
query
->
selectOption
!=
''
)
{
if
(
$this
->
query
->
selectOption
!=
=
null
)
{
$select
.=
' '
.
$this
->
query
->
selectOption
;
}
...
...
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