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
9d8a4012
Commit
9d8a4012
authored
Feb 10, 2012
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
...
parent
6d6d8d95
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
358 additions
and
517 deletions
+358
-517
YiiBase.php
framework/YiiBase.php
+5
-6
Model.php
framework/base/Model.php
+4
-4
ModelBehavior.php
framework/base/ModelBehavior.php
+2
-2
ModelEvent.php
framework/base/ModelEvent.php
+6
-7
Object.php
framework/base/Object.php
+1
-1
ActiveFinder.php
framework/db/ar/ActiveFinder.php
+28
-28
ActiveMetaData.php
framework/db/ar/ActiveMetaData.php
+24
-2
ActiveRecord.php
framework/db/ar/ActiveRecord.php
+273
-458
JoinElement.php
framework/db/ar/JoinElement.php
+2
-2
Text.php
framework/util/Text.php
+13
-7
No files found.
framework/YiiBase.php
View file @
9d8a4012
...
...
@@ -75,17 +75,16 @@ class YiiBase
);
/**
* @var array initial property values that will be applied to objects newly created via [[createObject]].
* The array keys are fully qualified namespaced class names, and the array values are the corresponding
* name-value pairs for initializing the created class instances. Please make sure class names are starting
* with a backslash. For example,
* The array keys are class names without leading backslashes "\", and the array values are the corresponding
* name-value pairs for initializing the created class instances. For example,
*
* ~~~
* array(
* '
\
Bar' => array(
* 'Bar' => array(
* 'prop1' => 'value1',
* 'prop2' => 'value2',
* ),
* '
\
mycompany\foo\Car' => array(
* 'mycompany\foo\Car' => array(
* 'prop1' => 'value1',
* 'prop2' => 'value2',
* ),
...
...
@@ -375,7 +374,7 @@ class YiiBase
$object
=
new
$class
;
}
$class
=
'\\'
.
get_class
(
$object
);
$class
=
get_class
(
$object
);
if
(
isset
(
\Yii
::
$objectConfig
[
$class
]))
{
$config
=
array_merge
(
\Yii
::
$objectConfig
[
$class
],
$config
);
...
...
framework/base/Model.php
View file @
9d8a4012
...
...
@@ -207,7 +207,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
public
function
beforeValidate
()
{
if
(
$this
->
hasEventHandlers
(
'onBeforeValidate'
))
{
$event
=
new
Validation
Event
(
$this
);
$event
=
new
Model
Event
(
$this
);
$this
->
onBeforeValidate
(
$event
);
return
$event
->
isValid
;
}
...
...
@@ -229,7 +229,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/**
* This event is raised before the validation is performed.
* @param
Validation
Event $event the event parameter
* @param
Model
Event $event the event parameter
*/
public
function
onBeforeValidate
(
$event
)
{
...
...
@@ -457,7 +457,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
*/
public
function
generateAttributeLabel
(
$name
)
{
return
Text
::
name
2words
(
$name
,
true
);
return
Text
::
camel
2words
(
$name
,
true
);
}
/**
...
...
@@ -583,7 +583,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/**
* Returns an iterator for traversing the attributes in the model.
* This method is required by the interface IteratorAggregate.
* @return
CMap
Iterator an iterator for traversing the items in the list.
* @return
Dictionary
Iterator an iterator for traversing the items in the list.
*/
public
function
getIterator
()
{
...
...
framework/base/ModelBehavior.php
View file @
9d8a4012
...
...
@@ -52,9 +52,9 @@ class ModelBehavior extends Behavior
/**
* Responds to [[Model::onBeforeValidate]] event.
* Override this method if you want to handle the corresponding event of the [[owner]].
* You may set the [[
Validation
Event::isValid|isValid]] property of the event parameter
* You may set the [[
Model
Event::isValid|isValid]] property of the event parameter
* to be false to cancel the validation process.
* @param
Validation
Event $event event parameter
* @param
Model
Event $event event parameter
*/
public
function
beforeValidate
(
$event
)
{
...
...
framework/base/
Validation
Event.php
→
framework/base/
Model
Event.php
View file @
9d8a4012
<?php
/**
*
Validation
Event class file.
*
Model
Event class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008-2012 Yii Software LLC
...
...
@@ -10,19 +10,18 @@
namespace
yii\base
;
/**
*
Validation
Event class.
*
Model
Event class.
*
*
ValidationEvent represents the parameter needed by model validation
events.
*
ModelEvent represents the parameter needed by model
events.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
Validation
Event
extends
Event
class
Model
Event
extends
Event
{
/**
* @var boolean whether the model passes the validation by the event handler.
* Defaults to true. If it is set false, the [[Model::validate|model validation]] will be cancelled.
* @see Model::onBeforeValidate
* @var boolean whether the model is in valid status. Defaults to true.
* A model is in valid status if it passes validation, or other checks.
*/
public
$isValid
=
true
;
}
framework/base/Object.php
View file @
9d8a4012
...
...
@@ -299,7 +299,7 @@ class Object
*/
public
static
function
newInstance
(
$config
=
array
())
{
$class
=
'\\'
.
get_called_class
();
$class
=
get_called_class
();
if
((
$n
=
func_num_args
())
>
1
)
{
$args
=
func_get_args
();
...
...
framework/db/ar/Active
Query
.php
→
framework/db/ar/Active
Finder
.php
View file @
9d8a4012
<?php
/**
* Active
Query
class file.
* Active
Finder
class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
...
...
@@ -18,10 +18,10 @@ use yii\db\Exception;
* ActiveFinder.php is ...
* todo: add SQL monitor
*
* todo: add Active
Query
Builder
* todo: add Active
Finder
Builder
* todo: quote join/on part of the relational query
* todo: modify QueryBuilder about join() methods
* todo: unify Active
Query
and ActiveRelation in query building process
* todo: unify Active
Finder
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
...
...
@@ -33,14 +33,14 @@ use yii\db\Exception;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
Active
Query
extends
\yii\base\Object
implements
\IteratorAggregate
,
\ArrayAccess
,
\Countable
class
Active
Finder
extends
\yii\base\Object
implements
\IteratorAggregate
,
\ArrayAccess
,
\Countable
{
/**
* @var string the name of the ActiveRecord class.
*/
public
$modelClass
;
/**
* @var
\yii\db\dao\
Query the Query object
* @var Query the Query object
*/
public
$query
;
/**
...
...
@@ -278,7 +278,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* (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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
select
(
$columns
,
$option
=
''
)
{
...
...
@@ -289,7 +289,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
/**
* Sets the value indicating whether to SELECT DISTINCT or not.
* @param bool $value whether to SELECT DISTINCT or not.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
distinct
(
$value
=
true
)
{
...
...
@@ -304,7 +304,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
from
(
$tables
)
{
...
...
@@ -379,7 +379,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* @param array $params the parameters (name=>value) to be bound to the query.
* For anonymous parameters, they can alternatively be specified as separate parameters to this method.
* For example, `where('type=? AND status=?', 100, 1)`.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see andWhere()
* @see orWhere()
*/
...
...
@@ -400,7 +400,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see where()
* @see orWhere()
*/
...
...
@@ -421,7 +421,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see where()
* @see andWhere()
*/
...
...
@@ -445,7 +445,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
join
(
$table
,
$condition
,
$params
=
array
())
{
...
...
@@ -466,7 +466,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* @param string|array $condition 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
leftJoin
(
$table
,
$condition
,
$params
=
array
())
{
...
...
@@ -487,7 +487,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* @param string|array $condition 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
rightJoin
(
$table
,
$condition
,
$params
=
array
())
{
...
...
@@ -506,7 +506,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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).
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
crossJoin
(
$table
)
{
...
...
@@ -521,7 +521,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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).
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
naturalJoin
(
$table
)
{
...
...
@@ -535,7 +535,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see addGroupBy()
*/
public
function
groupBy
(
$columns
)
...
...
@@ -550,7 +550,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see groupBy()
*/
public
function
addGroupBy
(
$columns
)
...
...
@@ -565,7 +565,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see andHaving()
* @see orHaving()
*/
...
...
@@ -586,7 +586,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see having()
* @see orHaving()
*/
...
...
@@ -607,7 +607,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see having()
* @see andHaving()
*/
...
...
@@ -627,7 +627,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see addOrderBy()
*/
public
function
orderBy
(
$columns
)
...
...
@@ -642,7 +642,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* 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 Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see orderBy()
*/
public
function
addOrderBy
(
$columns
)
...
...
@@ -654,7 +654,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
limit
(
$limit
)
{
...
...
@@ -665,7 +665,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
/**
* Sets the OFFSET part of the query.
* @param integer $offset the offset
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
offset
(
$offset
)
{
...
...
@@ -676,7 +676,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
/**
* Appends a SQL statement using UNION operator.
* @param string|Query $sql the SQL statement to be appended using UNION
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
*/
public
function
union
(
$sql
)
{
...
...
@@ -694,7 +694,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* @param array list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see addParams()
*/
public
function
params
(
$params
)
...
...
@@ -708,7 +708,7 @@ class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \Array
* @param array list of query parameter values indexed by parameter placeholders.
* For example, `array(':name'=>'Dan', ':age'=>31)`.
* Please refer to [[where()]] on alternative syntax of specifying anonymous parameters.
* @return Active
Query
the query object itself
* @return Active
Finder
the query object itself
* @see params()
*/
public
function
addParams
(
$params
)
...
...
framework/db/ar/ActiveMetaData.php
View file @
9d8a4012
...
...
@@ -14,6 +14,10 @@ use yii\db\dao\TableSchema;
class
ActiveMetaData
{
/**
* @var ActiveMetaData[] list of ActiveMetaData instances indexed by the model class names
*/
public
static
$instances
;
/**
* @var TableSchema the table schema information
*/
public
$table
;
...
...
@@ -27,14 +31,32 @@ class ActiveMetaData
public
$relations
=
array
();
/**
* Returns an instance of ActiveMetaData for the specified model class.
* Note that each model class only has a single ActiveMetaData instance.
* This method will only create the ActiveMetaData instance if it is not previously
* done so for the specified model class.
* @param string $modelClass the model class name. Make sure the class name do NOT have a leading backslash "\".
* @param boolean $refresh whether to recreate the ActiveMetaData instance. Defaults to false.
* @return ActiveMetaData the ActiveMetaData instance for the specified model class.
*/
public
static
function
getInstance
(
$modelClass
,
$refresh
=
false
)
{
if
(
isset
(
self
::
$instances
[
$modelClass
])
&&
!
$refresh
)
{
return
self
::
$instances
[
$modelClass
];
}
else
{
return
self
::
$instances
[
$modelClass
]
=
new
self
(
$modelClass
);
}
}
/**
* Constructor.
* @param string $modelClass the model class name
*/
public
function
__construct
(
$modelClass
)
{
$this
->
modelClass
=
$modelClass
;
$tableName
=
$modelClass
::
tableName
();
$this
->
table
=
$modelClass
::
getDbConnection
()
->
getDriver
()
->
getTableSchema
(
$tableName
);
$this
->
modelClass
=
$modelClass
;
if
(
$this
->
table
===
null
)
{
throw
new
Exception
(
"Unable to find table '
$tableName
' for ActiveRecord class '
$modelClass
'."
);
}
...
...
@@ -71,7 +93,7 @@ class ActiveMetaData
$relation
->
name
=
$matches
[
1
];
$modelClass
=
$matches
[
2
];
if
(
strpos
(
$modelClass
,
'\\'
)
!==
false
)
{
$relation
->
modelClass
=
'\\'
.
ltrim
(
$modelClass
,
'\\'
);
$relation
->
modelClass
=
ltrim
(
$modelClass
,
'\\'
);
}
else
{
$relation
->
modelClass
=
dirname
(
$this
->
modelClass
)
.
'\\'
.
$modelClass
;
}
...
...
framework/db/ar/ActiveRecord.php
View file @
9d8a4012
...
...
@@ -10,10 +10,15 @@
namespace
yii\db\ar
;
use
yii\base\Model
;
use
yii\base\Event
;
use
yii\base\ModelEvent
;
use
yii\db\Exception
;
use
yii\db\dao\Connection
;
use
yii\db\dao\TableSchema
;
use
yii\db\dao\Query
;
use
yii\db\dao\Expression
;
use
yii\util\Text
;
/**
* ActiveRecord is the base class for classes representing relational data.
...
...
@@ -23,18 +28,16 @@ use yii\db\dao\Query;
*
* @property array $attributes
*/
abstract
class
ActiveRecord
extends
\yii\base\
Model
abstract
class
ActiveRecord
extends
Model
{
/**
* @var ActiveMetaData[] list of AR metadata indexed by AR class names
* @var array attribute values indexed by attribute names
*/
private
$_attributes
=
array
();
/**
* @var array old attribute values indexed by attribute names.
*/
private
static
$_md
;
private
$_new
=
false
;
// whether this instance is new or not
private
$_attributes
=
array
();
// attribute name => attribute value
private
$_oldAttributes
;
private
$_related
=
array
();
// attribute name => related objects
private
$_pk
;
// old primary key value
/**
* Returns the metadata for this AR class.
...
...
@@ -43,78 +46,119 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
static
function
getMetaData
(
$refresh
=
false
)
{
$class
=
get_called_class
();
if
(
!
$refresh
&&
isset
(
self
::
$_md
[
$class
]))
{
return
self
::
$_md
[
$class
];
}
else
{
return
self
::
$_md
[
$class
]
=
new
ActiveMetaData
(
'\\'
.
$class
);
}
return
ActiveMetaData
::
getInstance
(
get_called_class
(),
$refresh
);
}
/**
* @param string|array|Query $q
* @return ActiveQuery
* @throws Exception
* Creates an [[ActiveFinder]] instance for query purpose.
*
* Because [[ActiveFinder]] implements a set of query building methods,
* additional query conditions can be specified by calling these methods.
*
* Below are some usage examples:
*
* ~~~
* // find all customers
* $customers = Customer::find()->all();
* // find a single customer whose ID 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();
* ~~~
*
* @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.
*
* @return ActiveFinder the [[ActiveFinder]] instance for query purpose.
* @throws Exception if the query parameter is invalid.
*/
public
static
function
find
(
$q
=
null
)
{
$
query
=
static
::
createActiveQuery
();
$
finder
=
static
::
createActiveFinder
();
if
(
$q
instanceof
Query
)
{
$
query
->
query
=
$q
;
$
finder
->
query
=
$q
;
}
elseif
(
is_array
(
$q
))
{
// query by a
ttribut
es
$
query
->
where
(
$q
);
// query by a
set of column valu
es
$
finder
->
where
(
$q
);
}
elseif
(
$q
!==
null
)
{
// query by primary key
$primaryKey
=
static
::
getMetaData
()
->
table
->
primaryKey
;
if
(
count
(
$primaryKey
)
===
1
)
{
$
query
->
where
(
array
(
$primaryKey
[
0
]
=>
$q
));
$
finder
->
where
(
array
(
$primaryKey
[
0
]
=>
$q
));
}
else
{
throw
new
Exception
(
'Multiple values are required to query by composite keys.'
);
throw
new
Exception
(
'Multiple values are required to query by composite
primary
keys.'
);
}
}
return
$
query
;
return
$
finder
;
}
/**
* Creates an [[ActiveFinder]] 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.
* @param string $sql the SQL statement to be executed
* @param array $params parameters to be bound to the SQL statement during execution.
* @return ActiveFinder the [[ActiveFinder]] instance
*/
public
static
function
findBySql
(
$sql
,
$params
=
array
())
{
if
(
!
is_array
(
$params
))
{
$params
=
func_get_args
();
array_shift
(
$params
);
unset
(
$params
[
0
]
);
}
$
query
=
static
::
createActiveQuery
();
$
query
->
sql
=
$sql
;
return
$
query
->
params
(
$params
);
$
finder
=
static
::
createActiveFinder
();
$
finder
->
sql
=
$sql
;
return
$
finder
->
params
(
$params
);
}
public
static
function
updateAll
()
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
();
}
public
static
function
updateCounters
()
public
static
function
updateCounters
(
$counters
,
$condition
=
''
,
$params
=
array
()
)
{
$class
=
get_called_class
();
$db
=
$class
::
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
();
}
public
static
function
deleteAll
()
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
();
}
/**
* @return ActiveFinder
* Creates a [[ActiveFinder]] instance.
* This method is mainly called by [[find()]] and [[findBySql()]].
* @return ActiveFinder the newly created [[ActiveFinder]] instance.
*/
public
static
function
createActiveFinder
()
{
return
new
ActiveFinder
(
'\\'
.
get_called_class
());
return
new
ActiveFinder
(
get_called_class
());
}
/**
* Returns the database connection used by
active record
.
* Returns the database connection used by
this AR class
.
* By default, the "db" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by
active record
.
* @return Connection the database connection used by
this AR class
.
*/
public
static
function
getDbConnection
()
{
...
...
@@ -122,36 +166,24 @@ abstract class ActiveRecord extends \yii\base\Model
}
/**
* Returns the default named scope that should be implicitly applied to all queries for this model.
* Note, default scope only applies to SELECT queries. It is ignored for INSERT, UPDATE and DELETE queries.
* The default implementation simply returns an empty array. You may override this method
* if the model needs to be queried with some default criteria (e.g. only active records should be returned).
* @return array the query criteria. This will be used as the parameter to the constructor
* of {@link CDbCriteria}.
*/
public
static
function
defaultScope
()
{
return
array
();
}
/**
* Returns the name of the associated database table.
* By default this method returns the class name as the table name.
* Declares the name of the database table associated with this AR class.
* By default this method returns the class name as the table name by calling [[Text::camel2id()]].
* For example, 'Customer' becomes 'customer', and 'OrderDetail' becomes 'order_detail'.
* You may override this method if the table is not named after this convention.
* @return string the table name
*/
public
static
function
tableName
()
{
return
basename
(
get_called_class
()
);
return
Text
::
camel2id
(
basename
(
get_called_class
()),
'_'
);
}
/**
*
Returns the primary key of the associated database table
.
*
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,
* you do not need to override this method. The default implementation simply returns null,
* meaning using the primary key defined in the database.
* @return
mixed
the primary key of the associated database table.
* meaning using the primary key defined in the database
table
.
* @return
string|array
the primary key of the associated database table.
* If the key is a single column, it should return the column name;
* If the key is a composite one consisting of several columns, it should
* return the array of the key column names.
...
...
@@ -161,22 +193,22 @@ abstract class ActiveRecord extends \yii\base\Model
}
/**
* Declares the relations for this A
ctiveRecord
class.
* Declares the relations for this A
R
class.
*
* Child classes may
want to
override this method to specify their relations.
* Child classes may override this method to specify their relations.
*
* The following shows how to declare relations for a
Programmer
AR class:
* The following shows how to declare relations for a
`Programmer`
AR class:
*
* ~~~
* return array(
* 'manager:Manager' => '
?.manager_id = manager.
id',
* 'manager:Manager' => '
@.id = ?.manager_
id',
* 'assignments:Assignment[]' => array(
* 'on' => '
?.id = assignments.owner_id AND assignments.status=
1',
* 'orderBy' => '
assignments
.create_time DESC',
* 'on' => '
@.owner_id = ?.id AND @.status =
1',
* 'orderBy' => '
@
.create_time DESC',
* ),
* 'projects:Project[]' => array(
* 'via' => 'assignments',
* 'on' => '
projects.id = assignments
.project_id',
* 'on' => '
@.id = ?
.project_id',
* ),
* );
* ~~~
...
...
@@ -265,6 +297,19 @@ abstract class ActiveRecord extends \yii\base\Model
}
/**
* Returns the default named scope that should be implicitly applied to all queries for this model.
* Note, default scope only applies to SELECT queries. It is ignored for INSERT, UPDATE and DELETE queries.
* The default implementation simply returns an empty array. You may override this method
* if the model needs to be queried with some default criteria (e.g. only active records should be returned).
* @return array the query criteria. This will be used as the parameter to the constructor
* of {@link CDbCriteria}.
*/
public
static
function
defaultScope
()
{
return
array
();
}
/**
* Returns the declaration of named scopes.
* A named scope represents a query criteria that can be chained together with
* other named scopes and applied to a query. This method should be overridden
...
...
@@ -301,50 +346,25 @@ abstract class ActiveRecord extends \yii\base\Model
}
/**
* Constructor.
* @param string $scenario scenario name. See {@link CModel::scenario} for more details about this parameter.
*/
public
function
__construct
(
$scenario
=
'insert'
)
{
if
(
$scenario
===
null
)
// internally used by populateData() and model()
{
return
;
}
$this
->
setScenario
(
$scenario
);
$this
->
setIsNewRecord
(
true
);
}
/**
* PHP sleep magic method.
* This method ensures that the model meta data reference is set to null.
* @return array
*/
public
function
__sleep
()
{
return
array_keys
((
array
)
$this
);
}
/**
* PHP getter magic method.
* This method is overridden so that
AR attribute
s can be accessed like properties.
* This method is overridden so that
attributes and related object
s can be accessed like properties.
* @param string $name property name
* @return mixed property value
* @see getAttribute
*/
public
function
__get
(
$name
)
{
if
(
isset
(
$this
->
_attributes
[
$name
]))
{
if
(
isset
(
$this
->
_attributes
[
$name
])
||
array_key_exists
(
$name
,
$this
->
_attributes
)
)
{
return
$this
->
_attributes
[
$name
];
}
elseif
(
isset
(
$this
->
getMetaData
()
->
table
->
columns
[
$name
]))
{
return
null
;
}
elseif
(
isset
(
$this
->
_related
[
$name
]))
{
return
$this
->
_related
[
$name
];
}
elseif
(
isset
(
$this
->
getMetaData
()
->
relations
[
$name
]))
{
return
$this
->
getRelatedRecord
(
$name
);
}
else
{
return
parent
::
__get
(
$name
);
$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
]);
}
}
return
parent
::
__get
(
$name
);
}
/**
...
...
@@ -355,10 +375,9 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
__set
(
$name
,
$value
)
{
if
(
isset
(
$this
->
getMetaData
()
->
table
->
columns
[
$name
]))
{
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
table
->
columns
[
$name
])
||
isset
(
$md
->
relations
[
$name
]))
{
$this
->
_attributes
[
$name
]
=
$value
;
}
elseif
(
isset
(
$this
->
getMetaData
()
->
relations
[
$name
]))
{
$this
->
_related
[
$name
]
=
$value
;
}
else
{
parent
::
__set
(
$name
,
$value
);
}
...
...
@@ -375,12 +394,8 @@ abstract class ActiveRecord extends \yii\base\Model
{
if
(
isset
(
$this
->
_attributes
[
$name
]))
{
return
true
;
}
elseif
(
isset
(
$this
->
getMetaData
()
->
colum
ns
[
$name
]))
{
}
elseif
(
isset
(
$this
->
getMetaData
()
->
table
->
columns
[
$name
])
||
isset
(
$this
->
getMetaData
()
->
relatio
ns
[
$name
]))
{
return
false
;
}
elseif
(
isset
(
$this
->
_related
[
$name
]))
{
return
true
;
}
elseif
(
isset
(
$this
->
getMetaData
()
->
relations
[
$name
]))
{
return
$this
->
getRelatedRecord
(
$name
)
!==
null
;
}
else
{
return
parent
::
__isset
(
$name
);
}
...
...
@@ -394,10 +409,9 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
__unset
(
$name
)
{
if
(
isset
(
$this
->
getMetaData
()
->
columns
[
$name
]))
{
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
table
->
columns
[
$name
])
||
isset
(
$md
->
relations
[
$name
]))
{
unset
(
$this
->
_attributes
[
$name
]);
}
elseif
(
isset
(
$this
->
getMetaData
()
->
relations
[
$name
]))
{
unset
(
$this
->
_related
[
$name
]);
}
else
{
parent
::
__unset
(
$name
);
}
...
...
@@ -408,39 +422,34 @@ abstract class ActiveRecord extends \yii\base\Model
* Do not call this method. This is a PHP magic method that we override
* to implement the named scope feature.
* @param string $name the method name
* @param array $param
eter
s method parameters
* @param array $params method parameters
* @return mixed the method return value
*/
public
function
__call
(
$name
,
$param
eter
s
)
public
function
__call
(
$name
,
$params
)
{
if
(
isset
(
$this
->
getMetaData
()
->
relations
[
$name
]))
{
if
(
empty
(
$parameters
))
{
return
$this
->
getRelatedRecord
(
$name
,
false
);
}
else
{
return
$this
->
getRelatedRecord
(
$name
,
false
,
$parameters
[
0
]);
}
}
$scopes
=
$this
->
scopes
();
if
(
isset
(
$scopes
[
$name
]))
{
$this
->
getDbCriteria
()
->
mergeWith
(
$scopes
[
$name
]);
return
$this
;
$md
=
$this
->
getMetaData
();
if
(
isset
(
$md
->
relations
[
$name
]))
{
return
$this
->
loadRelatedRecord
(
$md
->
relations
[
$name
],
isset
(
$params
[
0
])
?
$params
[
0
]
:
array
());
}
return
parent
::
__call
(
$name
,
$parameters
);
return
parent
::
__call
(
$name
,
$params
);
}
public
function
initRelatedRecord
(
$relation
)
/**
* Initializes the internal storage for the relation.
* This method is internally used by [[ActiveFinder]] when populating relation data.
* @param ActiveRelation $relation the relation object
*/
public
function
initRelation
(
$relation
)
{
$this
->
_
related
[
$relation
->
name
]
=
$relation
->
hasMany
?
array
()
:
null
;
$this
->
_
attributes
[
$relation
->
name
]
=
$relation
->
hasMany
?
array
()
:
null
;
}
public
function
addRelatedRecord
(
$relation
,
$record
)
{
if
(
$relation
->
hasMany
)
{
$this
->
_
related
[
$relation
->
name
][]
=
$record
;
$this
->
_
attributes
[
$relation
->
name
][]
=
$record
;
}
else
{
$this
->
_
related
[
$relation
->
name
]
=
$record
;
$this
->
_
attributes
[
$relation
->
name
]
=
$record
;
}
}
...
...
@@ -458,69 +467,16 @@ abstract class ActiveRecord extends \yii\base\Model
* @return mixed the related object(s).
* @throws Exception if the relation is not specified in {@link relations}.
*/
public
function
getRelatedRecord
(
$name
,
$refresh
=
false
,
$params
=
array
())
public
function
loadRelatedRecord
(
$relation
,
$params
=
array
())
{
if
(
!
$refresh
&&
$params
===
array
()
&&
(
isset
(
$this
->
_related
[
$name
])
||
array_key_exists
(
$name
,
$this
->
_related
)))
{
return
$this
->
_related
[
$name
];
}
$md
=
$this
->
getMetaData
();
if
(
!
isset
(
$md
->
relations
[
$name
]))
{
throw
new
Exception
(
Yii
::
t
(
'yii'
,
'{class} does not have relation "{name}".'
,
array
(
'{class}'
=>
get_class
(
$this
),
'{name}'
=>
$name
)));
}
Yii
::
trace
(
'lazy loading '
.
get_class
(
$this
)
.
'.'
.
$name
,
'system.db.ar.ActiveRecord'
);
$relation
=
$md
->
relations
[
$name
];
if
(
$this
->
getIsNewRecord
()
&&
!
$refresh
&&
(
$relation
instanceof
CHasOneRelation
||
$relation
instanceof
CHasManyRelation
))
{
return
$relation
instanceof
CHasOneRelation
?
null
:
array
();
}
if
(
$params
!==
array
())
// dynamic query
{
$exists
=
isset
(
$this
->
_related
[
$name
])
||
array_key_exists
(
$name
,
$this
->
_related
);
if
(
$exists
)
{
$save
=
$this
->
_related
[
$name
];
}
$r
=
array
(
$name
=>
$params
);
}
else
{
$r
=
$name
;
}
unset
(
$this
->
_related
[
$name
]);
$finder
=
new
CActiveFinder
(
$this
,
$r
);
$finder
->
lazyFind
(
$this
);
if
(
!
isset
(
$this
->
_related
[
$name
]))
{
if
(
$relation
instanceof
CHasManyRelation
)
{
$this
->
_related
[
$name
]
=
array
();
}
elseif
(
$relation
instanceof
CStatRelation
)
{
$this
->
_related
[
$name
]
=
$relation
->
defaultValue
;
}
else
{
$this
->
_related
[
$name
]
=
null
;
}
}
if
(
$params
!==
array
())
{
$results
=
$this
->
_related
[
$name
];
if
(
$exists
)
{
$this
->
_related
[
$name
]
=
$save
;
}
else
{
unset
(
$this
->
_related
[
$name
]);
if
(
is_string
(
$relation
))
{
$md
=
$this
->
getMetaData
();
if
(
!
isset
(
$md
->
relations
[
$relation
]))
{
throw
new
Exception
(
get_class
(
$this
)
.
' has no relation named "'
.
$relation
.
'".'
);
}
return
$results
;
}
else
{
return
$this
->
_related
[
$name
];
$relation
=
$md
->
relations
[
$relation
];
}
}
/**
* Returns a value indicating whether the named related object(s) has been loaded.
* @param string $name the relation name
* @return boolean a value indicating whether the named related object(s) has been loaded.
*/
public
function
hasRelated
(
$name
)
{
return
isset
(
$this
->
_related
[
$name
])
||
array_key_exists
(
$name
,
$this
->
_related
);
$finder
=
$this
->
createActiveFinder
();
}
/**
...
...
@@ -530,69 +486,7 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
attributeNames
()
{
return
array_keys
(
$this
->
getMetaData
()
->
columns
);
}
/**
* Returns the text label for the specified attribute.
* This method overrides the parent implementation by supporting
* returning the label defined in relational object.
* In particular, if the attribute name is in the form of "post.author.name",
* then this method will derive the label from the "author" relation's "name" attribute.
* @param string $attribute the attribute name
* @return string the attribute label
* @see generateAttributeLabel
*/
public
function
getAttributeLabel
(
$attribute
)
{
$labels
=
$this
->
attributeLabels
();
if
(
isset
(
$labels
[
$attribute
]))
{
return
$labels
[
$attribute
];
}
elseif
(
strpos
(
$attribute
,
'.'
)
!==
false
)
{
$segs
=
explode
(
'.'
,
$attribute
);
$name
=
array_pop
(
$segs
);
$model
=
$this
;
foreach
(
$segs
as
$seg
)
{
$relations
=
$model
->
getMetaData
()
->
relations
;
if
(
isset
(
$relations
[
$seg
]))
{
$model
=
ActiveRecord
::
model
(
$relations
[
$seg
]
->
className
);
}
else
{
break
;
}
}
return
$model
->
getAttributeLabel
(
$name
);
}
else
{
return
$this
->
generateAttributeLabel
(
$attribute
);
}
}
/**
* Returns the named relation declared for this AR class.
* @param string $name the relation name
* @return CActiveRelation the named relation declared for this AR class. Null if the relation does not exist.
*/
public
function
getActiveRelation
(
$name
)
{
return
isset
(
$this
->
getMetaData
()
->
relations
[
$name
])
?
$this
->
getMetaData
()
->
relations
[
$name
]
:
null
;
}
/**
* Returns the metadata of the table that this AR belongs to
* @return CDbTableSchema the metadata of the table that this AR belongs to
*/
public
function
getTableSchema
()
{
return
$this
->
getMetaData
()
->
tableSchema
;
}
/**
* Checks whether this AR has the named attribute
* @param string $name attribute name
* @return boolean whether this AR has the named attribute (table column).
*/
public
function
hasAttribute
(
$name
)
{
return
isset
(
$this
->
getMetaData
()
->
columns
[
$name
]);
return
array_keys
(
$this
->
getMetaData
()
->
table
->
columns
);
}
/**
...
...
@@ -608,11 +502,7 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
getAttribute
(
$name
)
{
if
(
property_exists
(
$this
,
$name
))
{
return
$this
->
$name
;
}
elseif
(
isset
(
$this
->
_attributes
[
$name
]))
{
return
$this
->
_attributes
[
$name
];
}
return
isset
(
$this
->
_attributes
[
$name
])
?
$this
->
_attributes
[
$name
]
:
null
;
}
/**
...
...
@@ -620,53 +510,47 @@ abstract class ActiveRecord extends \yii\base\Model
* You may also use $this->AttributeName to set the attribute value.
* @param string $name the attribute name
* @param mixed $value the attribute value.
* @return boolean whether the attribute exists and the assignment is conducted successfully
* @see hasAttribute
*/
public
function
setAttribute
(
$name
,
$value
)
{
if
(
property_exists
(
$this
,
$name
))
{
$this
->
$name
=
$value
;
}
elseif
(
isset
(
$this
->
getMetaData
()
->
table
->
columns
[
$name
]))
{
$this
->
_attributes
[
$name
]
=
$value
;
}
else
{
return
false
;
}
return
true
;
$this
->
_attributes
[
$name
]
=
$value
;
}
/**
* Returns all column attribute values.
* Note, related objects are not returned.
* @param
mixed
$names names of attributes whose value needs to be returned.
* @param
null|array
$names names of attributes whose value needs to be returned.
* If this is true (default), then all attribute values will be returned, including
* those that are not loaded from DB (null will be returned for those attributes).
* If this is null, all attributes except those that are not loaded from DB will be returned.
* @return array attribute values indexed by attribute names.
*/
public
function
getAttributes
(
$names
=
true
)
public
function
getAttributes
(
$names
=
null
)
{
$attributes
=
$this
->
_attributes
;
foreach
(
$this
->
getMetaData
()
->
columns
as
$name
=>
$column
)
{
if
(
property_exists
(
$this
,
$name
))
{
$attributes
[
$name
]
=
$this
->
$name
;
}
elseif
(
$names
===
true
&&
!
isset
(
$attributes
[
$name
]))
{
$attributes
[
$name
]
=
null
;
}
if
(
$names
===
null
)
{
$names
=
$this
->
attributeNames
();
}
if
(
is_array
(
$names
))
{
$attrs
=
array
();
foreach
(
$names
as
$name
)
{
if
(
property_exists
(
$this
,
$name
))
{
$attrs
[
$name
]
=
$this
->
$name
;
}
else
{
$attrs
[
$name
]
=
isset
(
$attributes
[
$name
])
?
$attributes
[
$name
]
:
null
;
}
$values
=
array
();
foreach
(
$names
as
$name
)
{
$values
[
$name
]
=
isset
(
$this
->
_attributes
[
$name
])
?
$this
->
_attributes
[
$name
]
:
null
;
}
return
$values
;
}
public
function
getChangedAttributes
(
$names
=
null
)
{
if
(
$names
===
null
)
{
$names
=
$this
->
attributeNames
();
}
$names
=
array_flip
(
$names
);
$attributes
=
array
();
foreach
(
$this
->
_attributes
as
$name
=>
$value
)
{
if
(
isset
(
$names
[
$name
])
&&
(
!
array_key_exists
(
$name
,
$this
->
_oldAttributes
)
||
$value
!==
$this
->
_oldAttributes
[
$name
]))
{
$attributes
[
$name
]
=
$value
;
}
return
$attrs
;
}
else
{
return
$attributes
;
}
return
$attributes
;
}
/**
...
...
@@ -710,7 +594,7 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
getIsNewRecord
()
{
return
$this
->
_new
;
return
empty
(
$this
->
_oldAttributes
)
;
}
/**
...
...
@@ -720,13 +604,22 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
setIsNewRecord
(
$value
)
{
$this
->
_new
=
$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 event is raised before the record is saved.
* By setting {@link
C
ModelEvent::isValid} to be false, the normal {@link save()} process will be stopped.
* @param
C
ModelEvent $event the event parameter
* By setting {@link ModelEvent::isValid} to be false, the normal {@link save()} process will be stopped.
* @param ModelEvent $event the event parameter
*/
public
function
onBeforeSave
(
$event
)
{
...
...
@@ -735,7 +628,7 @@ abstract class ActiveRecord extends \yii\base\Model
/**
* This event is raised after the record is saved.
* @param
C
Event $event the event parameter
* @param Event $event the event parameter
*/
public
function
onAfterSave
(
$event
)
{
...
...
@@ -744,8 +637,8 @@ abstract class ActiveRecord extends \yii\base\Model
/**
* This event is raised before the record is deleted.
* By setting {@link
C
ModelEvent::isValid} to be false, the normal {@link delete()} process will be stopped.
* @param
C
ModelEvent $event the event parameter
* By setting {@link ModelEvent::isValid} to be false, the normal {@link delete()} process will be stopped.
* @param ModelEvent $event the event parameter
*/
public
function
onBeforeDelete
(
$event
)
{
...
...
@@ -754,7 +647,7 @@ abstract class ActiveRecord extends \yii\base\Model
/**
* This event is raised after the record is deleted.
* @param
C
Event $event the event parameter
* @param Event $event the event parameter
*/
public
function
onAfterDelete
(
$event
)
{
...
...
@@ -770,15 +663,11 @@ abstract class ActiveRecord extends \yii\base\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.
*/
p
rotected
function
beforeSave
()
p
ublic
function
beforeSave
()
{
if
(
$this
->
hasEventHandler
(
'onBeforeSave'
))
{
$event
=
new
CModelEvent
(
$this
);
$this
->
onBeforeSave
(
$event
);
return
$event
->
isValid
;
}
else
{
return
true
;
}
$event
=
new
ModelEvent
(
$this
);
$this
->
onBeforeSave
(
$event
);
return
$event
->
isValid
;
}
/**
...
...
@@ -787,11 +676,9 @@ abstract class ActiveRecord extends \yii\base\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.
*/
p
rotected
function
afterSave
()
p
ublic
function
afterSave
()
{
if
(
$this
->
hasEventHandler
(
'onAfterSave'
))
{
$this
->
onAfterSave
(
new
CEvent
(
$this
));
}
$this
->
onAfterSave
(
new
Event
(
$this
));
}
/**
...
...
@@ -801,15 +688,11 @@ abstract class ActiveRecord extends \yii\base\Model
* Make sure you call the parent implementation so that the event is raised properly.
* @return boolean whether the record should be deleted. Defaults to true.
*/
p
rotected
function
beforeDelete
()
p
ublic
function
beforeDelete
()
{
if
(
$this
->
hasEventHandler
(
'onBeforeDelete'
))
{
$event
=
new
CModelEvent
(
$this
);
$this
->
onBeforeDelete
(
$event
);
return
$event
->
isValid
;
}
else
{
return
true
;
}
$event
=
new
ModelEvent
(
$this
);
$this
->
onBeforeDelete
(
$event
);
return
$event
->
isValid
;
}
/**
...
...
@@ -818,45 +701,9 @@ abstract class ActiveRecord extends \yii\base\Model
* You may override this method to do postprocessing after the record is deleted.
* Make sure you call the parent implementation so that the event is raised properly.
*/
p
rotected
function
afterDelete
()
p
ublic
function
afterDelete
()
{
if
(
$this
->
hasEventHandler
(
'onAfterDelete'
))
{
$this
->
onAfterDelete
(
new
CEvent
(
$this
));
}
}
/**
* This method is invoked before an AR finder executes a find call.
* The find calls include {@link find}, {@link findAll}, {@link findByPk},
* {@link findAllByPk}, {@link findByAttributes} and {@link findAllByAttributes}.
* The default implementation raises the {@link onBeforeFind} event.
* If you override this method, make sure you call the parent implementation
* so that the event is raised properly.
*
* Starting from version 1.1.5, this method may be called with a hidden {@link CDbCriteria}
* parameter which represents the current query criteria as passed to a find method of AR.
*/
protected
function
beforeFind
()
{
if
(
$this
->
hasEventHandler
(
'onBeforeFind'
))
{
$event
=
new
CModelEvent
(
$this
);
// for backward compatibility
$event
->
criteria
=
func_num_args
()
>
0
?
func_get_arg
(
0
)
:
null
;
$this
->
onBeforeFind
(
$event
);
}
}
/**
* This method is invoked after each record is instantiated by a find method.
* The default implementation raises the {@link onAfterFind} event.
* You may override this method to do postprocessing after each newly found record is instantiated.
* Make sure you call the parent implementation so that the event is raised properly.
*/
protected
function
afterFind
()
{
if
(
$this
->
hasEventHandler
(
'onAfterFind'
))
{
$this
->
onAfterFind
(
new
CEvent
(
$this
));
}
$this
->
onAfterDelete
(
new
Event
(
$this
));
}
/**
...
...
@@ -869,36 +716,30 @@ abstract class ActiveRecord extends \yii\base\Model
* @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
C
Exception if the record is not new
* @throws Exception if the record is not new
*/
public
function
insert
(
$attributes
=
null
)
{
if
(
!
$this
->
getIsNewRecord
())
{
throw
new
Exception
(
Yii
::
t
(
'yii'
,
'The active record cannot be inserted to database because it is not new.'
));
}
if
(
$this
->
beforeSave
())
{
Yii
::
trace
(
get_class
(
$this
)
.
'.insert()'
,
'system.db.ar.ActiveRecord'
);
$
builder
=
$this
->
getCommandBuilder
()
;
$
table
=
$this
->
getMetaData
()
->
tableSchema
;
$command
=
$
builder
->
createInsertCommand
(
$table
,
$this
->
getAttributes
(
$attributes
)
);
$db
=
$this
->
getDbConnection
(
);
$
query
=
new
Query
;
$
values
=
$this
->
getChangedAttributes
(
$attributes
)
;
$command
=
$
query
->
insert
(
$this
->
tableName
(),
$values
)
->
createCommand
(
$db
);
if
(
$command
->
execute
())
{
$
primaryKey
=
$table
->
primaryKey
;
$
table
=
$this
->
getMetaData
()
->
table
;
if
(
$table
->
sequenceName
!==
null
)
{
if
(
is_string
(
$primaryKey
)
&&
$this
->
$primaryKey
===
null
)
{
$this
->
$primaryKey
=
$builder
->
getLastInsertID
(
$table
);
}
elseif
(
is_array
(
$primaryKey
))
{
foreach
(
$primaryKey
as
$pk
)
{
if
(
$this
->
$pk
===
null
)
{
$this
->
$pk
=
$builder
->
getLastInsertID
(
$table
);
break
;
}
foreach
(
$table
->
primaryKey
as
$name
)
{
if
(
$this
->
$name
===
null
)
{
$this
->
_attributes
[
$name
]
=
$db
->
getLastInsertID
(
$table
->
sequenceName
);
break
;
}
}
}
$this
->
_pk
=
$this
->
getPrimaryKey
();
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
];
}
$this
->
afterSave
();
$this
->
setIsNewRecord
(
false
);
$this
->
setScenario
(
'update'
);
return
true
;
}
}
...
...
@@ -912,21 +753,20 @@ abstract class ActiveRecord extends \yii\base\Model
* @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
C
Exception if the record is new
* @throws Exception if the record is new
*/
public
function
update
(
$attributes
=
null
)
{
if
(
$this
->
getIsNewRecord
())
{
throw
new
Exception
(
Yii
::
t
(
'yii'
,
'The active record cannot be updated because it is new.'
));
}
if
(
$this
->
beforeSave
())
{
Yii
::
trace
(
get_class
(
$this
)
.
'.update()'
,
'system.db.ar.ActiveRecord'
);
if
(
$this
->
_pk
===
null
)
{
$this
->
_pk
=
$this
->
getPrimaryKey
();
$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
->
updateByPk
(
$this
->
getOldPrimaryKey
(),
$this
->
getAttributes
(
$attributes
));
$this
->
_pk
=
$this
->
getPrimaryKey
();
$this
->
afterSave
();
$this
->
setIsNewRecord
(
false
);
return
true
;
}
else
{
return
false
;
...
...
@@ -936,25 +776,26 @@ abstract class ActiveRecord extends \yii\base\Model
/**
* Saves a selected list of attributes.
* Unlike {@link save}, this method only saves the specified attributes
* of an existing row
dataset
and does NOT call either {@link beforeSave} or {@link afterSave}.
* Also note that this method does n
either attribute filtering nor validation
.
* of an existing row and does NOT call either {@link beforeSave} or {@link afterSave}.
* Also note that this method does n
ot 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:
* <pre>
* $postRecord=Post::model()->findByPk($postID);
* $postRecord->attributes=$_POST['post'];
* $postRecord->save();
* </pre>
*
* ~~~
* $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
C
Exception if the record is new or any database error
* @throws Exception if the record is new or any database error
*/
public
function
saveAttributes
(
$attributes
)
{
if
(
!
$this
->
getIsNewRecord
())
{
Yii
::
trace
(
get_class
(
$this
)
.
'.saveAttributes()'
,
'system.db.ar.ActiveRecord'
);
$values
=
array
();
foreach
(
$attributes
as
$name
=>
$value
)
{
if
(
is_integer
(
$name
))
{
...
...
@@ -963,17 +804,13 @@ abstract class ActiveRecord extends \yii\base\Model
$values
[
$name
]
=
$this
->
$name
=
$value
;
}
}
if
(
$this
->
_pk
===
null
)
{
$this
->
_pk
=
$this
->
getPrimaryKey
();
}
if
(
$this
->
updateByPk
(
$this
->
getOldPrimaryKey
(),
$values
)
>
0
)
{
$this
->
_pk
=
$this
->
getPrimaryKey
();
return
true
;
}
else
{
return
false
;
$this
->
updateAll
(
$values
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$value
;
}
return
true
;
}
else
{
throw
new
Exception
(
Yii
::
t
(
'yii'
,
'The active record cannot be updated because it is new.'
)
);
throw
new
Exception
(
'The active record cannot be updated because it is new.'
);
}
}
...
...
@@ -993,59 +830,55 @@ abstract class ActiveRecord extends \yii\base\Model
*/
public
function
saveCounters
(
$counters
)
{
Yii
::
trace
(
get_class
(
$this
)
.
'.saveCounters()'
,
'system.db.ar.ActiveRecord'
);
$builder
=
$this
->
getCommandBuilder
();
$table
=
$this
->
getTableSchema
();
$criteria
=
$builder
->
createPkCriteria
(
$table
,
$this
->
getOldPrimaryKey
());
$command
=
$builder
->
createUpdateCounterCommand
(
$this
->
getTableSchema
(),
$counters
,
$criteria
);
if
(
$command
->
execute
())
{
if
(
!
$this
->
getIsNewRecord
())
{
$this
->
updateCounters
(
$counters
,
$this
->
getOldPrimaryKey
(
true
));
foreach
(
$counters
as
$name
=>
$value
)
{
$this
->
$name
=
$this
->
$name
+
$value
;
$this
->
$name
+=
$value
;
$this
->
_oldAttributes
[
$name
]
=
$this
->
$name
;
}
return
true
;
}
else
{
return
false
;
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
C
Exception if the record is new
* @throws Exception if the record is new
*/
public
function
delete
()
{
if
(
!
$this
->
getIsNewRecord
())
{
Yii
::
trace
(
get_class
(
$this
)
.
'.delete()'
,
'system.db.ar.ActiveRecord'
);
if
(
$this
->
beforeDelete
())
{
$result
=
$this
->
deleteByPk
(
$this
->
getPrimaryKey
())
>
0
;
$result
=
$this
->
deleteAll
(
$this
->
getPrimaryKey
(
true
))
>
0
;
$this
->
_oldAttributes
=
null
;
$this
->
afterDelete
();
return
$result
;
}
else
{
return
false
;
}
}
else
{
throw
new
Exception
(
Yii
::
t
(
'yii'
,
'The active record cannot be deleted because it is new.'
)
);
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
()
public
function
refresh
(
$attributes
=
null
)
{
Yii
::
trace
(
get_class
(
$this
)
.
'.refresh()'
,
'system.db.ar.ActiveRecord'
);
if
(
!
$this
->
getIsNewRecord
()
&&
(
$record
=
$this
->
findByPk
(
$this
->
getPrimaryKey
()))
!==
null
)
{
if
(
!
$this
->
getIsNewRecord
()
&&
(
$record
=
$this
->
find
(
$this
->
getPrimaryKey
(
true
)))
!==
null
)
{
if
(
$attributes
===
null
)
{
$attributes
=
$this
->
attributeNames
();
}
$this
->
_attributes
=
array
();
$this
->
_related
=
array
();
foreach
(
$this
->
getMetaData
()
->
columns
as
$name
=>
$column
)
{
if
(
property_exists
(
$this
,
$name
))
{
$this
->
$name
=
$record
->
$name
;
}
else
{
$this
->
_attributes
[
$name
]
=
$record
->
$name
;
}
foreach
(
$attributes
as
$name
)
{
$this
->
_attributes
[
$name
]
=
$record
->
_attributes
[
$name
];
}
$this
->
_oldAttributes
=
$this
->
_attributes
;
return
true
;
}
else
{
return
false
;
...
...
@@ -1065,13 +898,15 @@ abstract class ActiveRecord extends \yii\base\Model
/**
* Returns the primary key 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 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
getPrimaryKey
()
public
function
getPrimaryKey
(
$asArray
=
false
)
{
$table
=
static
::
getMetaData
()
->
table
;
if
(
count
(
$table
->
primaryKey
)
===
1
)
{
if
(
count
(
$table
->
primaryKey
)
===
1
&&
!
$asArray
)
{
return
$this
->
{
$table
->
primaryKey
[
0
]};
}
else
{
$values
=
array
();
...
...
@@ -1083,44 +918,27 @@ abstract class ActiveRecord extends \yii\base\Model
}
/**
* Sets the primary key value.
* After calling this method, the old primary key value can be obtained from {@link oldPrimaryKey}.
* @param mixed $value the new primary key value. If the primary key is composite, the new value
* should be provided as an array (column name=>column value).
*/
public
function
setPrimaryKey
(
$value
)
{
$this
->
_pk
=
$this
->
getPrimaryKey
();
$table
=
$this
->
getMetaData
()
->
table
;
if
(
count
(
$table
->
primaryKey
)
===
1
)
{
$this
->
{
$table
->
primaryKey
[
0
]}
=
$value
;
}
else
{
foreach
(
$table
->
primaryKey
as
$name
)
{
$this
->
$name
=
$value
[
$name
];
}
}
}
/**
* Returns the old primary key value.
* This refers to the primary key value that is populated into the record
* after executing a find method (e.g. find(), findAll()).
* 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 primary key is not defined, null will be returned.
*/
public
function
getOldPrimaryKey
()
public
function
getOldPrimaryKey
(
$asArray
=
false
)
{
return
$this
->
_pk
;
}
/**
* Sets the old primary key value.
* @param mixed $value the old primary key value.
*/
public
function
setOldPrimaryKey
(
$value
)
{
$this
->
_pk
=
$value
;
$table
=
static
::
getMetaData
()
->
table
;
if
(
count
(
$table
->
primaryKey
)
===
1
&&
!
$asArray
)
{
return
isset
(
$this
->
_oldAttributes
[
$table
->
primaryKey
[
0
]])
?
$this
->
_oldAttributes
[
$table
->
primaryKey
[
0
]]
:
null
;
}
else
{
$values
=
array
();
foreach
(
$table
->
primaryKey
as
$name
)
{
$values
[
$name
]
=
isset
(
$this
->
_oldAttributes
[
$name
])
?
$this
->
_oldAttributes
[
$name
]
:
null
;
}
return
$values
;
}
}
/**
...
...
@@ -1135,16 +953,13 @@ abstract class ActiveRecord extends \yii\base\Model
public
static
function
populateData
(
$row
)
{
$record
=
static
::
instantiate
(
$row
);
$record
->
setScenario
(
'update'
);
$columns
=
static
::
getMetaData
()
->
table
->
columns
;
foreach
(
$row
as
$name
=>
$value
)
{
if
(
property_exists
(
$record
,
$name
))
{
$record
->
$name
=
$value
;
}
elseif
(
isset
(
$columns
[
$name
]))
{
if
(
isset
(
$columns
[
$name
]))
{
$record
->
_attributes
[
$name
]
=
$value
;
}
}
$record
->
_
pk
=
$record
->
getPrimaryKey
()
;
$record
->
_
oldAttributes
=
$record
->
_attributes
;
return
$record
;
}
...
...
@@ -1158,7 +973,7 @@ abstract class ActiveRecord extends \yii\base\Model
* @param array $row list of attribute values for the active records.
* @return ActiveRecord the active record
*/
p
rotected
static
function
instantiate
(
$row
)
p
ublic
static
function
instantiate
(
$row
)
{
return
static
::
newInstance
();
}
...
...
framework/db/ar/JoinElement.php
View file @
9d8a4012
<?php
/**
*
ActiveQuery
class file.
*
JoinElement
class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
...
...
@@ -80,7 +80,7 @@ class JoinElement extends \yii\base\Object
$record
=
$modelClass
::
populateData
(
$attributes
);
foreach
(
$this
->
children
as
$child
)
{
if
(
$child
->
relation
->
select
!==
false
)
{
$record
->
initRelat
edRecord
(
$child
->
relation
);
$record
->
initRelat
ion
(
$child
->
relation
);
}
}
$this
->
records
[
$pk
]
=
$record
;
...
...
framework/util/Text.php
View file @
9d8a4012
...
...
@@ -57,26 +57,32 @@ class Text
}
/**
* Converts a
class
name into space-separated words.
* For example, 'PostTag' will be converted
as
'Post Tag'.
* Converts a
CamelCase
name into space-separated words.
* For example, 'PostTag' will be converted
to
'Post Tag'.
* @param string $name the string to be converted
* @param boolean $ucwords whether to capitalize the first letter in each word
* @return string the resulting words
*/
public
static
function
name
2words
(
$name
,
$ucwords
=
true
)
public
static
function
camel
2words
(
$name
,
$ucwords
=
true
)
{
$label
=
trim
(
strtolower
(
str_replace
(
array
(
'-'
,
'_'
,
'.'
),
' '
,
preg_replace
(
'/(?<![A-Z])[A-Z]/'
,
' \0'
,
$name
))));
return
$ucwords
?
ucwords
(
$label
)
:
$label
;
}
/**
* Converts a class name into a HTML ID.
* For example, 'PostTag' will be converted as 'post-tag'.
* Converts a CamelCase name into an ID in lowercase.
* Words in the ID may be concatenated using the specified character (defaults to '-').
* For example, 'PostTag' will be converted to 'post-tag'.
* @param string $name the string to be converted
* @param string $separator the character used to concatenate the words in the ID
* @return string the resulting ID
*/
public
static
function
name2id
(
$name
)
public
static
function
camel2id
(
$name
,
$separator
=
'-'
)
{
return
trim
(
strtolower
(
str_replace
(
'_'
,
'-'
,
preg_replace
(
'/(?<![A-Z])[A-Z]/'
,
'-\0'
,
$name
))),
'-'
);
if
(
$separator
===
'_'
)
{
return
trim
(
strtolower
(
preg_replace
(
'/(?<![A-Z])[A-Z]/'
,
'_\0'
,
$name
)),
'_'
);
}
else
{
return
trim
(
strtolower
(
str_replace
(
'_'
,
$separator
,
preg_replace
(
'/(?<![A-Z])[A-Z]/'
,
$separator
.
'\0'
,
$name
))),
$separator
);
}
}
}
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