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
96e794b4
Commit
96e794b4
authored
Dec 03, 2013
by
Paul Klimov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of github.com:yiisoft/yii2 into mongo
parents
dfefd060
3db7a075
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
290 additions
and
838 deletions
+290
-838
README.md
apps/advanced/README.md
+1
-1
README.md
apps/basic/README.md
+1
-1
requirements.php
apps/basic/requirements.php
+7
-0
controller.md
docs/guide/controller.md
+1
-1
url.md
docs/guide/url.md
+2
-2
Module.php
extensions/debug/Module.php
+2
-1
Panel.php
extensions/debug/Panel.php
+6
-0
DefaultController.php
extensions/debug/controllers/DefaultController.php
+10
-1
Command.php
extensions/elasticsearch/Command.php
+1
-1
Connection.php
extensions/elasticsearch/Connection.php
+28
-19
DebugAction.php
extensions/elasticsearch/DebugAction.php
+77
-0
DebugPanel.php
extensions/elasticsearch/DebugPanel.php
+48
-39
README-debug.png
extensions/elasticsearch/README-debug.png
+0
-0
README.md
extensions/elasticsearch/README.md
+3
-0
Generator.php
extensions/gii/generators/crud/Generator.php
+0
-1
Generator.php
extensions/gii/generators/model/Generator.php
+2
-2
ActiveRecord.php
extensions/sphinx/ActiveRecord.php
+13
-738
yii.activeForm.js
framework/yii/assets/yii.activeForm.js
+0
-1
Query.php
framework/yii/db/Query.php
+3
-0
BaseArrayHelper.php
framework/yii/helpers/BaseArrayHelper.php
+23
-0
BaseHtml.php
framework/yii/helpers/BaseHtml.php
+22
-6
ActiveRecord.php
tests/unit/data/ar/sphinx/ActiveRecord.php
+1
-1
ArticleDb.php
tests/unit/data/ar/sphinx/ArticleDb.php
+1
-1
ArticleIndex.php
tests/unit/data/ar/sphinx/ArticleIndex.php
+1
-1
ItemDb.php
tests/unit/data/ar/sphinx/ItemDb.php
+1
-1
ItemIndex.php
tests/unit/data/ar/sphinx/ItemIndex.php
+1
-1
RuntimeIndex.php
tests/unit/data/ar/sphinx/RuntimeIndex.php
+1
-1
TagDb.php
tests/unit/data/ar/sphinx/TagDb.php
+1
-1
ActiveDataProviderTest.php
tests/unit/extensions/sphinx/ActiveDataProviderTest.php
+2
-2
ActiveRecordTest.php
tests/unit/extensions/sphinx/ActiveRecordTest.php
+7
-8
ActiveRelationTest.php
tests/unit/extensions/sphinx/ActiveRelationTest.php
+3
-3
ExternalActiveRelationTest.php
tests/unit/extensions/sphinx/ExternalActiveRelationTest.php
+4
-4
ArrayHelperTest.php
tests/unit/framework/helpers/ArrayHelperTest.php
+17
-0
No files found.
apps/advanced/README.md
View file @
96e794b4
...
...
@@ -70,7 +70,7 @@ at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix).
You can then install the application using the following command:
~~~
php composer.phar create-project --stability=
alpha
yiisoft/yii2-app-advanced advanced
php composer.phar create-project --stability=
dev
yiisoft/yii2-app-advanced advanced
~~~
...
...
apps/basic/README.md
View file @
96e794b4
...
...
@@ -52,7 +52,7 @@ at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix).
You can then install this application template using the following command:
~~~
php composer.phar create-project --stability=
alpha
yiisoft/yii2-app-basic basic
php composer.phar create-project --stability=
dev
yiisoft/yii2-app-basic basic
~~~
Now you should be able to access the application through the following URL, assuming
`basic`
is the directory
...
...
apps/basic/requirements.php
View file @
96e794b4
...
...
@@ -48,6 +48,13 @@ $requirements = [
'by'
=>
'All <a href="http://www.yiiframework.com/doc/api/#system.db">DB-related classes</a>'
,
'memo'
=>
'Required for MySQL database.'
,
],
[
'name'
=>
'PDO PostgreSQL extension'
,
'mandatory'
=>
false
,
'condition'
=>
extension_loaded
(
'pdo_pgsql'
),
'by'
=>
'All <a href="http://www.yiiframework.com/doc/api/#system.db">DB-related classes</a>'
,
'memo'
=>
'Required for PostgreSQL database.'
,
],
// Cache :
[
'name'
=>
'Memcache extension'
,
...
...
docs/guide/controller.md
View file @
96e794b4
...
...
@@ -125,7 +125,7 @@ class BlogController extends Controller
throw
new
NotFoundHttpException
;
}
if
(
\Yii
::
$app
->
request
->
isPost
)
)
{
if
(
\Yii
::
$app
->
request
->
isPost
)
{
$post
->
load
(
$_POST
);
if
(
$post
->
save
())
{
$this
->
redirect
([
'view'
,
'id'
=>
$post
->
id
]);
...
...
docs/guide/url.md
View file @
96e794b4
...
...
@@ -2,8 +2,8 @@ URL Management
==============
The concept of URL management in Yii fairly simple. URL management is based on the premise that the application uses internal routes and parameters
everywhere. The framework itself will then translates routes into URLs, and translate URLs into routs, according to the URL manager's configuration.
This approach allows you to change site-wide URLs merely by edit
ed
a single config file, without ever touching the application code.
everywhere. The framework itself will then translates routes into URLs, and translate URLs into rout
e
s, according to the URL manager's configuration.
This approach allows you to change site-wide URLs merely by edit
ing
a single config file, without ever touching the application code.
Internal route
--------------
...
...
extensions/debug/Module.php
View file @
96e794b4
...
...
@@ -61,7 +61,8 @@ class Module extends \yii\base\Module
Yii
::
$app
->
getView
()
->
on
(
View
::
EVENT_END_BODY
,
[
$this
,
'renderToolbar'
]);
});
foreach
(
array_merge
(
$this
->
corePanels
(),
$this
->
panels
)
as
$id
=>
$config
)
{
$this
->
panels
=
array_merge
(
$this
->
corePanels
(),
$this
->
panels
);
foreach
(
$this
->
panels
as
$id
=>
$config
)
{
$config
[
'module'
]
=
$this
;
$config
[
'id'
]
=
$id
;
$this
->
panels
[
$id
]
=
Yii
::
createObject
(
$config
);
...
...
extensions/debug/Panel.php
View file @
96e794b4
...
...
@@ -31,6 +31,12 @@ class Panel extends Component
*/
public
$module
;
public
$data
;
/**
* @var array array of actions to add to the debug modules default controller.
* This array will be merged with all other panels actions property.
* See [[yii\base\Controller::actions()]] for the format.
*/
public
$actions
=
[];
/**
* @return string name of the panel
...
...
extensions/debug/controllers/DefaultController.php
View file @
96e794b4
...
...
@@ -27,6 +27,15 @@ class DefaultController extends Controller
*/
public
$summary
;
public
function
actions
()
{
$actions
=
[];
foreach
(
$this
->
module
->
panels
as
$panel
)
{
$actions
=
array_merge
(
$actions
,
$panel
->
actions
);
}
return
$actions
;
}
public
function
actionIndex
()
{
return
$this
->
render
(
'index'
,
[
'manifest'
=>
$this
->
getManifest
()]);
...
...
@@ -82,7 +91,7 @@ class DefaultController extends Controller
return
$this
->
_manifest
;
}
p
rotected
function
loadData
(
$tag
)
p
ublic
function
loadData
(
$tag
)
{
$manifest
=
$this
->
getManifest
();
if
(
isset
(
$manifest
[
$tag
]))
{
...
...
extensions/elasticsearch/Command.php
View file @
96e794b4
...
...
@@ -94,7 +94,7 @@ class Command extends Component
*/
public
function
get
(
$index
,
$type
,
$id
,
$options
=
[])
{
return
$this
->
db
->
get
([
$index
,
$type
,
$id
],
$options
,
null
,
[
200
,
404
]
);
return
$this
->
db
->
get
([
$index
,
$type
,
$id
],
$options
,
null
);
}
/**
...
...
extensions/elasticsearch/Connection.php
View file @
96e794b4
...
...
@@ -177,10 +177,10 @@ class Connection extends Component
return
new
QueryBuilder
(
$this
);
}
public
function
get
(
$url
,
$options
=
[],
$body
=
null
)
public
function
get
(
$url
,
$options
=
[],
$body
=
null
,
$raw
=
false
)
{
$this
->
open
();
return
$this
->
httpRequest
(
'GET'
,
$this
->
createUrl
(
$url
,
$options
),
$body
);
return
$this
->
httpRequest
(
'GET'
,
$this
->
createUrl
(
$url
,
$options
),
$body
,
$raw
);
}
public
function
head
(
$url
,
$options
=
[],
$body
=
null
)
...
...
@@ -189,37 +189,43 @@ class Connection extends Component
return
$this
->
httpRequest
(
'HEAD'
,
$this
->
createUrl
(
$url
,
$options
),
$body
);
}
public
function
post
(
$url
,
$options
=
[],
$body
=
null
)
public
function
post
(
$url
,
$options
=
[],
$body
=
null
,
$raw
=
false
)
{
$this
->
open
();
return
$this
->
httpRequest
(
'POST'
,
$this
->
createUrl
(
$url
,
$options
),
$body
);
return
$this
->
httpRequest
(
'POST'
,
$this
->
createUrl
(
$url
,
$options
),
$body
,
$raw
);
}
public
function
put
(
$url
,
$options
=
[],
$body
=
null
)
public
function
put
(
$url
,
$options
=
[],
$body
=
null
,
$raw
=
false
)
{
$this
->
open
();
return
$this
->
httpRequest
(
'PUT'
,
$this
->
createUrl
(
$url
,
$options
),
$body
);
return
$this
->
httpRequest
(
'PUT'
,
$this
->
createUrl
(
$url
,
$options
),
$body
,
$raw
);
}
public
function
delete
(
$url
,
$options
=
[],
$body
=
null
)
public
function
delete
(
$url
,
$options
=
[],
$body
=
null
,
$raw
=
false
)
{
$this
->
open
();
return
$this
->
httpRequest
(
'DELETE'
,
$this
->
createUrl
(
$url
,
$options
),
$body
);
return
$this
->
httpRequest
(
'DELETE'
,
$this
->
createUrl
(
$url
,
$options
),
$body
,
$raw
);
}
private
function
createUrl
(
$path
,
$options
=
[])
{
$url
=
implode
(
'/'
,
array_map
(
function
(
$a
)
{
return
urlencode
(
is_array
(
$a
)
?
implode
(
','
,
$a
)
:
$a
);
},
$path
));
if
(
!
empty
(
$options
))
{
$url
.=
'?'
.
http_build_query
(
$options
);
if
(
!
is_string
(
$path
))
{
$url
=
implode
(
'/'
,
array_map
(
function
(
$a
)
{
return
urlencode
(
is_array
(
$a
)
?
implode
(
','
,
$a
)
:
$a
);
},
$path
));
if
(
!
empty
(
$options
))
{
$url
.=
'?'
.
http_build_query
(
$options
);
}
}
else
{
$url
=
$path
;
if
(
!
empty
(
$options
))
{
$url
.=
(
strpos
(
$url
,
'?'
)
===
false
?
'?'
:
'&'
)
.
http_build_query
(
$options
);
}
}
return
[
$this
->
nodes
[
$this
->
activeNode
][
'http_address'
],
$url
];
}
protected
function
httpRequest
(
$method
,
$url
,
$requestBody
=
null
)
protected
function
httpRequest
(
$method
,
$url
,
$requestBody
=
null
,
$raw
=
false
)
{
$method
=
strtoupper
(
$method
);
...
...
@@ -228,7 +234,7 @@ class Connection extends Component
$body
=
''
;
$options
=
[
CURLOPT_USERAGENT
=>
'Yii
2 Framework
'
.
__CLASS__
,
CURLOPT_USERAGENT
=>
'Yii
Framework 2
'
.
__CLASS__
,
CURLOPT_RETURNTRANSFER
=>
false
,
CURLOPT_HEADER
=>
false
,
// http://www.php.net/manual/en/function.curl-setopt.php#82418
...
...
@@ -264,8 +270,11 @@ class Connection extends Component
if
(
is_array
(
$url
))
{
list
(
$host
,
$q
)
=
$url
;
if
(
strncmp
(
$host
,
'inet[/'
,
6
)
==
0
)
{
$host
=
substr
(
$host
,
6
,
-
1
);
if
(
strncmp
(
$host
,
'inet['
,
5
)
==
0
)
{
$host
=
substr
(
$host
,
5
,
-
1
);
if
((
$pos
=
strpos
(
$host
,
'/'
))
!==
false
)
{
$host
=
substr
(
$host
,
$pos
+
1
);
}
}
$profile
=
$method
.
' '
.
$q
.
'#'
.
$requestBody
;
$url
=
'http://'
.
$host
.
'/'
.
$q
;
...
...
@@ -312,7 +321,7 @@ class Connection extends Component
]);
}
if
(
isset
(
$headers
[
'content-type'
])
&&
!
strncmp
(
$headers
[
'content-type'
],
'application/json'
,
16
))
{
return
Json
::
decode
(
$body
);
return
$raw
?
$body
:
Json
::
decode
(
$body
);
}
throw
new
Exception
(
'Unsupported data received from elasticsearch: '
.
$headers
[
'content-type'
],
[
'requestMethod'
=>
$method
,
...
...
extensions/elasticsearch/DebugAction.php
0 → 100644
View file @
96e794b4
<?php
/**
* @author Carsten Brandt <mail@cebe.cc>
*/
namespace
yii\elasticsearch
;
use
yii\base\Action
;
use
yii\base\NotSupportedException
;
use
yii\debug\Panel
;
use
yii\helpers\ArrayHelper
;
use
yii\web\HttpException
;
use
Yii
;
use
yii\web\Response
;
class
DebugAction
extends
Action
{
/**
* @var string the connection id to use
*/
public
$db
;
/**
* @var Panel
*/
public
$panel
;
public
function
run
(
$logId
,
$tag
)
{
$this
->
controller
->
loadData
(
$tag
);
$timings
=
$this
->
panel
->
calculateTimings
();
ArrayHelper
::
multisort
(
$timings
,
3
,
SORT_DESC
);
if
(
!
isset
(
$timings
[
$logId
]))
{
throw
new
HttpException
(
404
,
'Log message not found.'
);
}
$message
=
$timings
[
$logId
][
1
];
if
((
$pos
=
mb_strpos
(
$message
,
"#"
))
!==
false
)
{
$url
=
mb_substr
(
$message
,
0
,
$pos
);
$body
=
mb_substr
(
$message
,
$pos
+
1
);
}
else
{
$url
=
$message
;
$body
=
null
;
}
$method
=
mb_substr
(
$url
,
0
,
$pos
=
mb_strpos
(
$url
,
' '
));
$url
=
mb_substr
(
$url
,
$pos
+
1
);
$options
=
[
'pretty'
=>
true
];
/** @var Connection $db */
$db
=
\Yii
::
$app
->
getComponent
(
$this
->
db
);
$time
=
microtime
(
true
);
switch
(
$method
)
{
case
'GET'
:
$result
=
$db
->
get
(
$url
,
$options
,
$body
,
true
);
break
;
case
'POST'
:
$result
=
$db
->
post
(
$url
,
$options
,
$body
,
true
);
break
;
case
'PUT'
:
$result
=
$db
->
put
(
$url
,
$options
,
$body
,
true
);
break
;
case
'DELETE'
:
$result
=
$db
->
delete
(
$url
,
$options
,
$body
,
true
);
break
;
case
'HEAD'
:
$result
=
$db
->
head
(
$url
,
$options
,
$body
);
break
;
default
:
throw
new
NotSupportedException
(
"Request method '
$method
' is not supported by elasticsearch."
);
}
$time
=
microtime
(
true
)
-
$time
;
if
(
$result
===
true
)
{
$result
=
'<span class="label label-success">success</span>'
;
}
elseif
(
$result
===
false
)
{
$result
=
'<span class="label label-danger">no success</span>'
;
}
Yii
::
$app
->
response
->
format
=
Response
::
FORMAT_JSON
;
return
[
'time'
=>
sprintf
(
'%.1f ms'
,
$time
*
1000
),
'result'
=>
$result
,
];
}
}
\ No newline at end of file
extensions/elasticsearch/DebugPanel.php
View file @
96e794b4
...
...
@@ -8,6 +8,7 @@
namespace
yii\elasticsearch
;
use
yii\debug\Panel
;
use
yii\helpers\ArrayHelper
;
use
yii\log\Logger
;
use
yii\helpers\Html
;
use
yii\web\View
;
...
...
@@ -20,6 +21,17 @@ use yii\web\View;
*/
class
DebugPanel
extends
Panel
{
public
$db
=
'elasticsearch'
;
public
function
init
()
{
$this
->
actions
[
'elasticsearch-query'
]
=
[
'class'
=>
'yii\\elasticsearch\\DebugAction'
,
'panel'
=>
$this
,
'db'
=>
$this
->
db
,
];
}
public
function
getName
()
{
return
'Elasticsearch'
;
...
...
@@ -47,13 +59,14 @@ EOD;
public
function
getDetail
()
{
$timings
=
$this
->
calculateTimings
();
ArrayHelper
::
multisort
(
$timings
,
3
,
SORT_DESC
);
$rows
=
[];
$i
=
0
;
foreach
(
$this
->
data
[
'messages'
]
as
$log
)
{
list
(
$message
,
$level
,
$category
,
$time
,
$traces
)
=
$log
;
if
(
$level
==
Logger
::
LEVEL_PROFILE_BEGIN
)
{
continue
;
}
foreach
(
$timings
as
$logId
=>
$timing
)
{
$duration
=
sprintf
(
'%.1f ms'
,
$timing
[
3
]
*
1000
);
$message
=
$timing
[
1
];
$traces
=
$timing
[
4
];
if
((
$pos
=
mb_strpos
(
$message
,
"#"
))
!==
false
)
{
$url
=
mb_substr
(
$message
,
0
,
$pos
);
$body
=
mb_substr
(
$message
,
$pos
+
1
);
...
...
@@ -66,48 +79,43 @@ EOD;
$traceString
.=
Html
::
ul
(
$traces
,
[
'class'
=>
'trace'
,
'item'
=>
function
(
$trace
)
{
return
"<li>
{
$trace
[
'file'
]
}
(
{
$trace
[
'line'
]
}
)</li>"
;
},
return
"<li>
{
$trace
[
'file'
]
}
(
{
$trace
[
'line'
]
}
)</li>"
;
},
]);
}
$runLinks
=
''
;
$c
=
0
;
\Yii
::
$app
->
elasticsearch
->
open
();
foreach
(
\Yii
::
$app
->
elasticsearch
->
nodes
as
$node
)
{
$pos
=
mb_strpos
(
$url
,
' '
);
$type
=
mb_substr
(
$url
,
0
,
$pos
);
if
(
$type
==
'GET'
&&
!
empty
(
$body
))
{
$type
=
'POST'
;
}
$host
=
$node
[
'http_address'
];
if
(
strncmp
(
$host
,
'inet[/'
,
6
)
==
0
)
{
$host
=
substr
(
$host
,
6
,
-
1
);
}
$nodeUrl
=
'http://'
.
$host
.
'/'
.
mb_substr
(
$url
,
$pos
+
1
);
$nodeUrl
.=
(
strpos
(
$nodeUrl
,
'?'
)
===
false
)
?
'?pretty=true'
:
'&pretty=true'
;
$nodeBody
=
json_encode
(
$body
);
\Yii
::
$app
->
view
->
registerJs
(
<<<JS
$('#elastic-link-$i-$c').on('click', function() {
$('#elastic-result-$i').html('Sending $type request to $nodeUrl...');
$('#elastic-result-$i').parent('tr').show();
$ajaxUrl
=
Html
::
url
([
'elasticsearch-query'
,
'logId'
=>
$logId
,
'tag'
=>
$this
->
tag
]);
\Yii
::
$app
->
view
->
registerJs
(
<<<JS
$('#elastic-link-$i').on('click', function() {
var result = $('#elastic-result-$i');
result.html('Sending request...');
result.parent('tr').show();
$.ajax({
type: "$type",
url: "$nodeUrl",
body: $nodeBody,
type: "POST",
url: "$ajaxUrl",
success: function( data ) {
$('#elastic-result-$i').html(data);
$('#elastic-time-$i').html(data.time);
$('#elastic-result-$i').html(data.result);
},
dataType: "text"
error: function(jqXHR, textStatus, errorThrown) {
$('#elastic-time-$i').html('');
$('#elastic-result-$i').html('<span style="color: #c00;">Error: ' + errorThrown + ' - ' + textStatus + '</span><br />' + jqXHR.responseText);
},
dataType: "json"
});
return false;
});
JS
,
View
::
POS_READY
);
$runLinks
.=
Html
::
a
(
isset
(
$node
[
'name'
])
?
$node
[
'name'
]
:
$node
[
'http_address'
],
'#'
,
[
'id'
=>
"elastic-link-
$i
-
$c
"
])
.
'<br/>'
;
$c
++
;
}
$rows
[]
=
"<tr><td style=
\"
width: 80%;
\"
><div><b>
$url
</b><br/><p>
$body
</p>
$traceString
</div></td><td style=
\"
width: 20%;
\"
>
$runLinks
</td></tr><tr style=
\"
display: none;
\"
><td colspan=
\"
2
\"
id=
\"
elastic-result-
$i
\"
></td></tr>"
;
$runLink
=
Html
::
a
(
'run query'
,
'#'
,
[
'id'
=>
"elastic-link-
$i
"
])
.
'<br/>'
;
$rows
[]
=
<<<HTML
<tr>
<td style="width: 10%;">$duration</td>
<td style="width: 75%;"><div><b>$url</b><br/><p>$body</p>$traceString</div></td>
<td style="width: 15%;">$runLink</td>
</tr>
<tr style="display: none;"><td id="elastic-time-$i"></td><td colspan="3" id="elastic-result-$i"></td></tr>
HTML;
$i
++
;
}
$rows
=
implode
(
"
\n
"
,
$rows
);
...
...
@@ -117,8 +125,9 @@ JS
<table class="table table-condensed table-bordered table-striped table-hover" style="table-layout: fixed;">
<thead>
<tr>
<th style="width: 80%;">Url / Query</th>
<th style="width: 20%;">Run Query on node</th>
<th style="width: 10%;">Time</th>
<th style="width: 75%;">Url / Query</th>
<th style="width: 15%;">Run Query on node</th>
</tr>
</thead>
<tbody>
...
...
@@ -130,7 +139,7 @@ HTML;
private
$_timings
;
p
rotected
function
calculateTimings
()
p
ublic
function
calculateTimings
()
{
if
(
$this
->
_timings
!==
null
)
{
return
$this
->
_timings
;
...
...
extensions/elasticsearch/README-debug.png
0 → 100644
View file @
96e794b4
105 KB
extensions/elasticsearch/README.md
View file @
96e794b4
...
...
@@ -172,3 +172,5 @@ Add the following to you application config to enable it:
],
// ...
```
![
elasticsearch DebugPanel
](
README-debug.png
)
\ No newline at end of file
extensions/gii/generators/crud/Generator.php
View file @
96e794b4
...
...
@@ -348,7 +348,6 @@ class Generator extends \yii\gii\Generator
case
Schema
::
TYPE_TIME
:
case
Schema
::
TYPE_DATETIME
:
case
Schema
::
TYPE_TIMESTAMP
:
case
$conditions
[]
=
"
\$
this->addCondition(
\$
query, '
{
$column
}
');"
;
break
;
default
:
...
...
extensions/gii/generators/model/Generator.php
View file @
96e794b4
...
...
@@ -397,10 +397,10 @@ class Generator extends \yii\gii\Generator
}
$name
=
$rawName
=
Inflector
::
id2camel
(
$key
,
'_'
);
$i
=
0
;
while
(
isset
(
$table
->
columns
[
$name
]))
{
while
(
isset
(
$table
->
columns
[
lcfirst
(
$name
)
]))
{
$name
=
$rawName
.
(
$i
++
);
}
while
(
isset
(
$relations
[
$className
][
$name
]))
{
while
(
isset
(
$relations
[
$className
][
lcfirst
(
$name
)
]))
{
$name
=
$rawName
.
(
$i
++
);
}
...
...
extensions/sphinx/ActiveRecord.php
View file @
96e794b4
...
...
@@ -8,11 +8,8 @@
namespace
yii\sphinx
;
use
yii\base\InvalidConfigException
;
use
yii\base\InvalidParamException
;
use
yii\base\Model
;
use
yii\base\ModelEvent
;
use
yii\db\BaseActiveRecord
;
use
yii\base\NotSupportedException
;
use
yii\base\UnknownMethodException
;
use
yii\db\ActiveRelationInterface
;
use
yii\db\StaleObjectException
;
use
yii\helpers\Inflector
;
...
...
@@ -22,6 +19,9 @@ use Yii;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
*
* Warning: optimistic lock will NOT work in case of updating fields (not attributes) for the
* runtime indexes!
*
* @property array $dirtyAttributes The changed attribute values (name-value pairs). This property is
* read-only.
* @property boolean $isNewRecord Whether the record is new and should be inserted when calling [[save()]].
...
...
@@ -40,45 +40,9 @@ use Yii;
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
abstract
class
ActiveRecord
extends
Model
abstract
class
ActiveRecord
extends
BaseActiveRecord
{
/**
* @event Event an event that is triggered when the record is initialized via [[init()]].
*/
const
EVENT_INIT
=
'init'
;
/**
* @event Event an event that is triggered after the record is created and populated with query result.
*/
const
EVENT_AFTER_FIND
=
'afterFind'
;
/**
* @event ModelEvent an event that is triggered before inserting a record.
* You may set [[ModelEvent::isValid]] to be false to stop the insertion.
*/
const
EVENT_BEFORE_INSERT
=
'beforeInsert'
;
/**
* @event Event an event that is triggered after a record is inserted.
*/
const
EVENT_AFTER_INSERT
=
'afterInsert'
;
/**
* @event ModelEvent an event that is triggered before updating a record.
* You may set [[ModelEvent::isValid]] to be false to stop the update.
*/
const
EVENT_BEFORE_UPDATE
=
'beforeUpdate'
;
/**
* @event Event an event that is triggered after a record is updated.
*/
const
EVENT_AFTER_UPDATE
=
'afterUpdate'
;
/**
* @event ModelEvent an event that is triggered before deleting a record.
* You may set [[ModelEvent::isValid]] to be false to stop the deletion.
*/
const
EVENT_BEFORE_DELETE
=
'beforeDelete'
;
/**
* @event Event an event that is triggered after a record is deleted.
*/
const
EVENT_AFTER_DELETE
=
'afterDelete'
;
/**
* The insert operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional.
*/
const
OP_INSERT
=
0x01
;
...
...
@@ -97,18 +61,6 @@ abstract class ActiveRecord extends Model
const
OP_ALL
=
0x07
;
/**
* @var array attribute values indexed by attribute names
*/
private
$_attributes
=
[];
/**
* @var array old attribute values indexed by attribute names.
*/
private
$_oldAttributes
;
/**
* @var array related models indexed by the relation names
*/
private
$_related
=
[];
/**
* @var string current snippet value for this Active Record instance.
* It will be filled up automatically when instance found using [[Query::snippetCallback]]
* or [[ActiveQuery::snippetByModel()]].
...
...
@@ -127,33 +79,6 @@ abstract class ActiveRecord extends Model
}
/**
* Creates an [[ActiveQuery]] instance for query purpose.
*
* @param mixed $q the query parameter. This can be one of the followings:
*
* - a string: fulltext query by a query string and return the list
* of matching records.
* - an array of name-value pairs: query by a set of column values and return a single record matching all of them.
* - null: return a new [[ActiveQuery]] object for further query purpose.
*
* @return ActiveQuery|ActiveRecord[]|ActiveRecord|null When `$q` is null, a new [[ActiveQuery]] instance
* is returned; when `$q` is a string, an array of ActiveRecord objects matching it will be returned;
* when `$q` is an array, an ActiveRecord object matching it will be returned (null
* will be returned if there is no matching).
* @see createQuery()
*/
public
static
function
find
(
$q
=
null
)
{
$query
=
static
::
createQuery
();
if
(
is_array
(
$q
))
{
return
$query
->
where
(
$q
)
->
one
();
}
elseif
(
$q
!==
null
)
{
return
$query
->
match
(
$q
)
->
all
();
}
return
$query
;
}
/**
* Creates an [[ActiveQuery]] instance with a given SQL statement.
*
* Note that because the SQL statement is already specified, calling additional
...
...
@@ -359,37 +284,6 @@ abstract class ActiveRecord extends Model
}
/**
* Returns the name of the column that stores the lock version for implementing optimistic locking.
*
* Optimistic locking allows multiple users to access the same record for edits and avoids
* potential conflicts. In case when a user attempts to save the record upon some staled data
* (because another user has modified the data), a [[StaleObjectException]] exception will be thrown,
* and the update or deletion is skipped.
*
* Optimistic locking is only supported by [[update()]] and [[delete()]].
*
* To use optimistic locking:
*
* 1. Create a column to store the version number of each row. The column type should be `BIGINT DEFAULT 0`.
* Override this method to return the name of this column.
* 2. In the Web form that collects the user input, add a hidden field that stores
* the lock version of the recording being updated.
* 3. In the controller action that does the data updating, try to catch the [[StaleObjectException]]
* and implement necessary business logic (e.g. merging the changes, prompting stated data)
* to resolve the conflict.
*
* Warning: optimistic lock will NOT work in case of updating fields (not attributes) for the
* runtime indexes!
*
* @return string the column name that stores the lock version of a table row.
* If null is returned (default implemented), optimistic locking will not be supported.
*/
public
function
optimisticLock
()
{
return
null
;
}
/**
* Declares which operations should be performed within a transaction in different scenarios.
* The supported DB operations are: [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]],
* which correspond to the [[insert()]], [[update()]] and [[delete()]] methods, respectively.
...
...
@@ -422,161 +316,6 @@ abstract class ActiveRecord extends Model
}
/**
* PHP getter magic method.
* This method is overridden so that attributes and related objects 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
])
||
array_key_exists
(
$name
,
$this
->
_attributes
))
{
return
$this
->
_attributes
[
$name
];
}
elseif
(
$this
->
hasAttribute
(
$name
))
{
return
null
;
}
else
{
if
(
isset
(
$this
->
_related
[
$name
])
||
array_key_exists
(
$name
,
$this
->
_related
))
{
return
$this
->
_related
[
$name
];
}
$value
=
parent
::
__get
(
$name
);
if
(
$value
instanceof
ActiveRelationInterface
)
{
return
$this
->
_related
[
$name
]
=
$value
->
multiple
?
$value
->
all
()
:
$value
->
one
();
}
else
{
return
$value
;
}
}
}
/**
* PHP setter magic method.
* This method is overridden so that AR attributes can be accessed like properties.
* @param string $name property name
* @param mixed $value property value
*/
public
function
__set
(
$name
,
$value
)
{
if
(
$this
->
hasAttribute
(
$name
))
{
$this
->
_attributes
[
$name
]
=
$value
;
}
else
{
parent
::
__set
(
$name
,
$value
);
}
}
/**
* Checks if a property value is null.
* This method overrides the parent implementation by checking if the named attribute is null or not.
* @param string $name the property name or the event name
* @return boolean whether the property value is null
*/
public
function
__isset
(
$name
)
{
try
{
return
$this
->
__get
(
$name
)
!==
null
;
}
catch
(
\Exception
$e
)
{
return
false
;
}
}
/**
* Sets a component property to be null.
* This method overrides the parent implementation by clearing
* the specified attribute value.
* @param string $name the property name or the event name
*/
public
function
__unset
(
$name
)
{
if
(
$this
->
hasAttribute
(
$name
))
{
unset
(
$this
->
_attributes
[
$name
]);
}
else
{
if
(
isset
(
$this
->
_related
[
$name
]))
{
unset
(
$this
->
_related
[
$name
]);
}
else
{
parent
::
__unset
(
$name
);
}
}
}
/**
* Declares a `has-one` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance
* through which the related record can be queried and retrieved back.
*
* A `has-one` relation means that there is at most one related record matching
* the criteria set by this relation, e.g., a particular index has one source.
*
* For example, to declare the `source` relation for `ArticleIndex` class, we can write
* the following code in the `ArticleIndex` class:
*
* ~~~
* public function getSource()
* {
* return $this->hasOne('db', ArticleContent::className(), ['article_id' => 'id']);
* }
* ~~~
*
* Note that in the above, the 'article_id' key in the `$link` parameter refers to an attribute name
* in the related class `ArticleContent`, while the 'id' value refers to an attribute name
* in the current AR class.
*
* Call methods declared in [[ActiveRelation]] to further customize the relation.
*
* @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to
* the attributes in the `$class` model, while the values of the array refer to the corresponding
* attributes in the index associated with this AR class.
* @return ActiveRelationInterface the relation object.
*/
public
function
hasOne
(
$class
,
$link
)
{
/** @var ActiveRecord $class */
return
$class
::
createActiveRelation
([
'modelClass'
=>
$class
,
'primaryModel'
=>
$this
,
'link'
=>
$link
,
'multiple'
=>
false
,
]);
}
/**
* Declares a `has-many` relation.
* The declaration is returned in terms of an [[ActiveRelationInterface]] instance
* through which the related record can be queried and retrieved back.
*
* A `has-many` relation means that there are multiple related records matching
* the criteria set by this relation, e.g., an article has many tags.
*
* For example, to declare the `tags` relation for `ArticleIndex` class, we can write
* the following code in the `ArticleIndex` class:
*
* ~~~
* public function getOrders()
* {
* return $this->hasMany('db', Tag::className(), ['id' => 'tag_id']);
* }
* ~~~
*
* Note that in the above, the 'id' key in the `$link` parameter refers to
* an attribute name in the related class `Tag`, while the 'tag_id' value refers to
* a multi value attribute name in the current AR class.
*
* @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to
* the columns in the table associated with the `$class` model, while the values of the
* array refer to the corresponding columns in the table associated with this AR class.
* @return ActiveRelationInterface the relation object.
*/
public
function
hasMany
(
$class
,
$link
)
{
/** @var ActiveRecord $class */
return
$class
::
createActiveRelation
([
'modelClass'
=>
$class
,
'primaryModel'
=>
$this
,
'link'
=>
$link
,
'multiple'
=>
true
,
]);
}
/**
* Creates an [[ActiveRelationInterface]] instance.
* This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance.
* You may override this method to return a customized relation.
...
...
@@ -589,36 +328,6 @@ abstract class ActiveRecord extends Model
}
/**
* Populates the named relation with the related records.
* Note that this method does not check if the relation exists or not.
* @param string $name the relation name (case-sensitive)
* @param ActiveRecord|array|null the related records to be populated into the relation.
*/
public
function
populateRelation
(
$name
,
$records
)
{
$this
->
_related
[
$name
]
=
$records
;
}
/**
* Check whether the named relation has been populated with records.
* @param string $name the relation name (case-sensitive)
* @return bool whether relation has been populated with records.
*/
public
function
isRelationPopulated
(
$name
)
{
return
array_key_exists
(
$name
,
$this
->
_related
);
}
/**
* Returns all populated relations.
* @return array an array of relation data indexed by relation names.
*/
public
function
getPopulatedRelations
()
{
return
$this
->
_related
;
}
/**
* Returns the list of all attribute names of the model.
* The default implementation will return all column names of the table associated with this AR class.
* @return array list of attribute names.
...
...
@@ -629,169 +338,6 @@ abstract class ActiveRecord extends Model
}
/**
* Returns a value indicating whether the model has an attribute with the specified name.
* @param string $name the name of the attribute
* @return boolean whether the model has an attribute with the specified name.
*/
public
function
hasAttribute
(
$name
)
{
return
isset
(
$this
->
_attributes
[
$name
])
||
in_array
(
$name
,
$this
->
attributes
());
}
/**
* Returns the named attribute value.
* If this record is the result of a query and the attribute is not loaded,
* null will be returned.
* @param string $name the attribute name
* @return mixed the attribute value. Null if the attribute is not set or does not exist.
* @see hasAttribute()
*/
public
function
getAttribute
(
$name
)
{
return
isset
(
$this
->
_attributes
[
$name
])
?
$this
->
_attributes
[
$name
]
:
null
;
}
/**
* Sets the named attribute value.
* @param string $name the attribute name
* @param mixed $value the attribute value.
* @throws InvalidParamException if the named attribute does not exist.
* @see hasAttribute()
*/
public
function
setAttribute
(
$name
,
$value
)
{
if
(
$this
->
hasAttribute
(
$name
))
{
$this
->
_attributes
[
$name
]
=
$value
;
}
else
{
throw
new
InvalidParamException
(
get_class
(
$this
)
.
' has no attribute named "'
.
$name
.
'".'
);
}
}
/**
* Returns the old attribute values.
* @return array the old attribute values (name-value pairs)
*/
public
function
getOldAttributes
()
{
return
$this
->
_oldAttributes
===
null
?
[]
:
$this
->
_oldAttributes
;
}
/**
* Sets the old attribute values.
* All existing old attribute values will be discarded.
* @param array $values old attribute values to be set.
*/
public
function
setOldAttributes
(
$values
)
{
$this
->
_oldAttributes
=
$values
;
}
/**
* Returns the old value of the named attribute.
* If this record is the result of a query and the attribute is not loaded,
* null will be returned.
* @param string $name the attribute name
* @return mixed the old attribute value. Null if the attribute is not loaded before
* or does not exist.
* @see hasAttribute()
*/
public
function
getOldAttribute
(
$name
)
{
return
isset
(
$this
->
_oldAttributes
[
$name
])
?
$this
->
_oldAttributes
[
$name
]
:
null
;
}
/**
* Sets the old value of the named attribute.
* @param string $name the attribute name
* @param mixed $value the old attribute value.
* @throws InvalidParamException if the named attribute does not exist.
* @see hasAttribute()
*/
public
function
setOldAttribute
(
$name
,
$value
)
{
if
(
isset
(
$this
->
_oldAttributes
[
$name
])
||
$this
->
hasAttribute
(
$name
))
{
$this
->
_oldAttributes
[
$name
]
=
$value
;
}
else
{
throw
new
InvalidParamException
(
get_class
(
$this
)
.
' has no attribute named "'
.
$name
.
'".'
);
}
}
/**
* Returns a value indicating whether the named attribute has been changed.
* @param string $name the name of the attribute
* @return boolean whether the attribute has been changed
*/
public
function
isAttributeChanged
(
$name
)
{
if
(
isset
(
$this
->
_attributes
[
$name
],
$this
->
_oldAttributes
[
$name
]))
{
return
$this
->
_attributes
[
$name
]
!==
$this
->
_oldAttributes
[
$name
];
}
else
{
return
isset
(
$this
->
_attributes
[
$name
])
||
isset
(
$this
->
_oldAttributes
[
$name
]);
}
}
/**
* Returns the attribute values that have been modified since they are loaded or saved most recently.
* @param string[]|null $names the names of the attributes whose values may be returned if they are
* changed recently. If null, [[attributes()]] will be used.
* @return array the changed attribute values (name-value pairs)
*/
public
function
getDirtyAttributes
(
$names
=
null
)
{
if
(
$names
===
null
)
{
$names
=
$this
->
attributes
();
}
$names
=
array_flip
(
$names
);
$attributes
=
[];
if
(
$this
->
_oldAttributes
===
null
)
{
foreach
(
$this
->
_attributes
as
$name
=>
$value
)
{
if
(
isset
(
$names
[
$name
]))
{
$attributes
[
$name
]
=
$value
;
}
}
}
else
{
foreach
(
$this
->
_attributes
as
$name
=>
$value
)
{
if
(
isset
(
$names
[
$name
])
&&
(
!
array_key_exists
(
$name
,
$this
->
_oldAttributes
)
||
$value
!==
$this
->
_oldAttributes
[
$name
]))
{
$attributes
[
$name
]
=
$value
;
}
}
}
return
$attributes
;
}
/**
* Saves the current record.
*
* This method will call [[insert()]] when [[isNewRecord]] is true, or [[update()]]
* when [[isNewRecord]] is false.
*
* For example, to save an article record:
*
* ~~~
* $customer = new Article; // or $customer = Article::find(['id' => $id]);
* $customer->id = $id;
* $customer->genre_id = $genreId;
* $customer->content = $email;
* $customer->save();
* ~~~
*
*
* @param boolean $runValidation whether to perform validation before saving the record.
* If the validation fails, the record will not be saved.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from index will be saved.
* @return boolean whether the saving succeeds
*/
public
function
save
(
$runValidation
=
true
,
$attributes
=
null
)
{
if
(
$this
->
getIsNewRecord
())
{
return
$this
->
insert
(
$runValidation
,
$attributes
);
}
else
{
return
$this
->
update
(
$runValidation
,
$attributes
)
!==
false
;
}
}
/**
* Inserts a row into the associated Sphinx index using the attribute values of this record.
*
* This method performs the following steps in order:
...
...
@@ -862,8 +408,8 @@ abstract class ActiveRecord extends Model
}
$values
=
$this
->
getDirtyAttributes
(
$attributes
);
if
(
empty
(
$values
))
{
foreach
(
$this
->
primaryKey
()
as
$key
)
{
$values
[
$key
]
=
isset
(
$this
->
_attributes
[
$key
])
?
$this
->
_attributes
[
$key
]
:
null
;
foreach
(
$this
->
getPrimaryKey
(
true
)
as
$key
=>
$value
)
{
$values
[
$key
]
=
$value
;
}
}
$db
=
static
::
getDb
();
...
...
@@ -872,7 +418,7 @@ abstract class ActiveRecord extends Model
return
false
;
}
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$value
;
$this
->
setOldAttribute
(
$name
,
$value
)
;
}
$this
->
afterSave
(
true
);
return
true
;
...
...
@@ -957,7 +503,7 @@ abstract class ActiveRecord extends Model
* @see CActiveRecord::update()
* @throws StaleObjectException
*/
pr
ivate
function
updateInternal
(
$attributes
=
null
)
pr
otected
function
updateInternal
(
$attributes
=
null
)
{
if
(
!
$this
->
beforeSave
(
false
))
{
return
false
;
...
...
@@ -1007,7 +553,7 @@ abstract class ActiveRecord extends Model
}
foreach
(
$values
as
$name
=>
$value
)
{
$this
->
_oldAttributes
[
$name
]
=
$this
->
_attributes
[
$name
]
;
$this
->
setOldAttribute
(
$name
,
$this
->
getAttribute
(
$name
))
;
}
$this
->
afterSave
(
false
);
return
$rows
;
...
...
@@ -1050,7 +596,7 @@ abstract class ActiveRecord extends Model
if
(
$lock
!==
null
&&
!
$result
)
{
throw
new
StaleObjectException
(
'The object being deleted is outdated.'
);
}
$this
->
_oldAttributes
=
null
;
$this
->
setOldAttributes
(
null
)
;
$this
->
afterDelete
();
}
if
(
$transaction
!==
null
)
{
...
...
@@ -1070,149 +616,6 @@ abstract class ActiveRecord extends Model
}
/**
* Returns a value indicating whether the current record is new.
* @return boolean whether the record is new and should be inserted when calling [[save()]].
*/
public
function
getIsNewRecord
()
{
return
$this
->
_oldAttributes
===
null
;
}
/**
* Sets the value indicating whether the record is new.
* @param boolean $value whether the record is new and should be inserted when calling [[save()]].
* @see getIsNewRecord()
*/
public
function
setIsNewRecord
(
$value
)
{
$this
->
_oldAttributes
=
$value
?
null
:
$this
->
_attributes
;
}
/**
* Initializes the object.
* This method is called at the end of the constructor.
* The default implementation will trigger an [[EVENT_INIT]] event.
* If you override this method, make sure you call the parent implementation at the end
* to ensure triggering of the event.
*/
public
function
init
()
{
parent
::
init
();
$this
->
trigger
(
self
::
EVENT_INIT
);
}
/**
* This method is called when the AR object is created and populated with the query result.
* The default implementation will trigger an [[EVENT_AFTER_FIND]] event.
* When overriding this method, make sure you call the parent implementation to ensure the
* event is triggered.
*/
public
function
afterFind
()
{
$this
->
trigger
(
self
::
EVENT_AFTER_FIND
);
}
/**
* This method is called at the beginning of inserting or updating a record.
* The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true,
* or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false.
* When overriding this method, make sure you call the parent implementation like the following:
*
* ~~~
* public function beforeSave($insert)
* {
* if (parent::beforeSave($insert)) {
* // ...custom code here...
* return true;
* } else {
* return false;
* }
* }
* ~~~
*
* @param boolean $insert whether this method called while inserting a record.
* If false, it means the method is called while updating a record.
* @return boolean whether the insertion or updating should continue.
* If false, the insertion or updating will be cancelled.
*/
public
function
beforeSave
(
$insert
)
{
$event
=
new
ModelEvent
;
$this
->
trigger
(
$insert
?
self
::
EVENT_BEFORE_INSERT
:
self
::
EVENT_BEFORE_UPDATE
,
$event
);
return
$event
->
isValid
;
}
/**
* This method is called at the end of inserting or updating a record.
* The default implementation will trigger an [[EVENT_AFTER_INSERT]] event when `$insert` is true,
* or an [[EVENT_AFTER_UPDATE]] event if `$insert` is false.
* When overriding this method, make sure you call the parent implementation so that
* the event is triggered.
* @param boolean $insert whether this method called while inserting a record.
* If false, it means the method is called while updating a record.
*/
public
function
afterSave
(
$insert
)
{
$this
->
trigger
(
$insert
?
self
::
EVENT_AFTER_INSERT
:
self
::
EVENT_AFTER_UPDATE
);
}
/**
* This method is invoked before deleting a record.
* The default implementation raises the [[EVENT_BEFORE_DELETE]] event.
* When overriding this method, make sure you call the parent implementation like the following:
*
* ~~~
* public function beforeDelete()
* {
* if (parent::beforeDelete()) {
* // ...custom code here...
* return true;
* } else {
* return false;
* }
* }
* ~~~
*
* @return boolean whether the record should be deleted. Defaults to true.
*/
public
function
beforeDelete
()
{
$event
=
new
ModelEvent
;
$this
->
trigger
(
self
::
EVENT_BEFORE_DELETE
,
$event
);
return
$event
->
isValid
;
}
/**
* This method is invoked after deleting a record.
* The default implementation raises the [[EVENT_AFTER_DELETE]] event.
* 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.
*/
public
function
afterDelete
()
{
$this
->
trigger
(
self
::
EVENT_AFTER_DELETE
);
}
/**
* Repopulates this active record with the latest data.
* @return boolean whether the row still exists in the database. If true, the latest data
* will be populated to this active record. Otherwise, this record will remain unchanged.
*/
public
function
refresh
()
{
$record
=
$this
->
find
(
$this
->
getPrimaryKey
(
true
));
if
(
$record
===
null
)
{
return
false
;
}
foreach
(
$this
->
attributes
()
as
$name
)
{
$this
->
_attributes
[
$name
]
=
isset
(
$record
->
_attributes
[
$name
])
?
$record
->
_attributes
[
$name
]
:
null
;
}
$this
->
_oldAttributes
=
$this
->
_attributes
;
$this
->
_related
=
[];
return
true
;
}
/**
* Returns a value indicating whether the given active record is the same as the current one.
* The comparison is made by comparing the index names and the primary key values of the two active records.
* If one of the records [[isNewRecord|is new]] they are also considered not equal.
...
...
@@ -1228,61 +631,6 @@ abstract class ActiveRecord extends Model
}
/**
* Returns the primary key value(s).
* @param boolean $asArray whether to return the primary key value as an array. If true,
* the return value will be an array with column names as keys and column values as values.
* Note that for composite primary keys, an array will always be returned regardless of this parameter value.
* @property mixed The primary key value. An array (column name => column value) is returned if
* the primary key is composite. A string is returned otherwise (null will be returned if
* the key value is null).
* @return mixed the primary key value. An array (column name => column value) is returned if the primary key
* is composite or `$asArray` is true. A string is returned otherwise (null will be returned if
* the key value is null).
*/
public
function
getPrimaryKey
(
$asArray
=
false
)
{
$keys
=
$this
->
primaryKey
();
if
(
count
(
$keys
)
===
1
&&
!
$asArray
)
{
return
isset
(
$this
->
_attributes
[
$keys
[
0
]])
?
$this
->
_attributes
[
$keys
[
0
]]
:
null
;
}
else
{
$values
=
[];
foreach
(
$keys
as
$name
)
{
$values
[
$name
]
=
isset
(
$this
->
_attributes
[
$name
])
?
$this
->
_attributes
[
$name
]
:
null
;
}
return
$values
;
}
}
/**
* Returns the old primary key value(s).
* 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.
* If this is false (default), a scalar value will be returned for non-composite primary key.
* @property mixed The old primary key value. An array (column name => column value) is
* returned if the primary key is composite. A string is returned otherwise (null will be
* returned if the key value is null).
* @return mixed the old primary key value. An array (column name => column value) is returned if the primary key
* is composite or `$asArray` is true. A string is returned otherwise (null will be returned if
* the key value is null).
*/
public
function
getOldPrimaryKey
(
$asArray
=
false
)
{
$keys
=
$this
->
primaryKey
();
if
(
count
(
$keys
)
===
1
&&
!
$asArray
)
{
return
isset
(
$this
->
_oldAttributes
[
$keys
[
0
]])
?
$this
->
_oldAttributes
[
$keys
[
0
]]
:
null
;
}
else
{
$values
=
[];
foreach
(
$keys
as
$name
)
{
$values
[
$name
]
=
isset
(
$this
->
_oldAttributes
[
$name
])
?
$this
->
_oldAttributes
[
$name
]
:
null
;
}
return
$values
;
}
}
/**
* Creates an active record object using a row of data.
* This method is called by [[ActiveQuery]] to populate the query results
* into Active Records. It is not meant to be used to create new records.
...
...
@@ -1299,64 +647,17 @@ abstract class ActiveRecord extends Model
if
(
$column
->
isMva
)
{
$value
=
explode
(
','
,
$value
);
}
$record
->
_attributes
[
$name
]
=
$value
;
$record
->
setAttribute
(
$name
,
$value
)
;
}
else
{
$record
->
$name
=
$value
;
}
}
$record
->
_oldAttributes
=
$record
->
_attributes
;
$record
->
setOldAttributes
(
$record
->
getAttributes
())
;
$record
->
afterFind
();
return
$record
;
}
/**
* Creates an active record instance.
* This method is called by [[create()]].
* You may override this method if the instance being created
* depends on the row data to be populated into the record.
* @param array $row row data to be populated into the record.
* @return ActiveRecord the newly created active record
*/
public
static
function
instantiate
(
$row
)
{
return
new
static
;
}
/**
* Returns whether there is an element at the specified offset.
* This method is required by the interface ArrayAccess.
* @param mixed $offset the offset to check on
* @return boolean whether there is an element at the specified offset.
*/
public
function
offsetExists
(
$offset
)
{
return
$this
->
__isset
(
$offset
);
}
/**
* Returns the relation object with the specified name.
* A relation is defined by a getter method which returns an [[ActiveRelationInterface]] object.
* It can be declared in either the Active Record class itself or one of its behaviors.
* @param string $name the relation name
* @return ActiveRelationInterface the relation object
* @throws InvalidParamException if the named relation does not exist.
*/
public
function
getRelation
(
$name
)
{
$getter
=
'get'
.
$name
;
try
{
$relation
=
$this
->
$getter
();
if
(
$relation
instanceof
ActiveRelationInterface
)
{
return
$relation
;
}
else
{
throw
new
InvalidParamException
(
get_class
(
$this
)
.
' has no relation named "'
.
$name
.
'".'
);
}
}
catch
(
UnknownMethodException
$e
)
{
throw
new
InvalidParamException
(
get_class
(
$this
)
.
' has no relation named "'
.
$name
.
'".'
,
0
,
$e
);
}
}
/**
* Returns a value indicating whether the specified operation is transactional in the current [[scenario]].
* @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]].
* @return boolean whether the specified operation is transactional in the current [[scenario]].
...
...
@@ -1367,29 +668,4 @@ abstract class ActiveRecord extends Model
$transactions
=
$this
->
transactions
();
return
isset
(
$transactions
[
$scenario
])
&&
(
$transactions
[
$scenario
]
&
$operation
);
}
/**
* Sets the element at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$model[$offset] = $item;`.
* @param integer $offset the offset to set element
* @param mixed $item the element value
* @throws \Exception on failure
*/
public
function
offsetSet
(
$offset
,
$item
)
{
// Bypass relation owner restriction to 'yii\db\ActiveRecord' at [[yii\db\ActiveRelationTrait::findWith()]]:
try
{
$relation
=
$this
->
getRelation
(
$offset
);
if
(
is_object
(
$relation
))
{
$this
->
populateRelation
(
$offset
,
$item
);
return
;
}
}
catch
(
InvalidParamException
$e
)
{
// shut down exception : has getter, but not relation
}
catch
(
UnknownMethodException
$e
)
{
throw
$e
->
getPrevious
();
}
parent
::
offsetSet
(
$offset
,
$item
);
}
}
\ No newline at end of file
framework/yii/assets/yii.activeForm.js
View file @
96e794b4
...
...
@@ -128,7 +128,6 @@
data
=
$form
.
data
(
'yiiActiveForm'
);
if
(
data
.
validated
)
{
// continue submitting the form since validation passes
data
.
validated
=
false
;
return
true
;
}
...
...
framework/yii/db/Query.php
View file @
96e794b4
...
...
@@ -23,10 +23,13 @@ use yii\base\Component;
*
* ~~~
* $query = new Query;
* // compose the query
* $query->select('id, name')
* ->from('tbl_user')
* ->limit(10);
* // build and execute the query
* $rows = $query->all();
* // alternatively, you can create DB command and execute it
* $command = $query->createCommand();
* // $command->sql returns the actual SQL
* $rows = $command->queryAll();
...
...
framework/yii/helpers/BaseArrayHelper.php
View file @
96e794b4
...
...
@@ -327,6 +327,29 @@ class BaseArrayHelper
}
/**
* Checks if the given array contains the specified key.
* This method enhances the `array_key_exists()` function by supporting case-insensitive
* key comparison.
* @param string $key the key to check
* @param array $array the array with keys to check
* @param boolean $caseSensitive whether the key comparison should be case-sensitive
* @return boolean whether the array contains the specified key
*/
public
static
function
keyExists
(
$key
,
$array
,
$caseSensitive
=
true
)
{
if
(
$caseSensitive
)
{
return
array_key_exists
(
$key
,
$array
);
}
else
{
foreach
(
array_keys
(
$array
)
as
$k
)
{
if
(
strcasecmp
(
$key
,
$k
)
===
0
)
{
return
true
;
}
}
return
false
;
}
}
/**
* Sorts an array of objects or arrays (with the same structure) by one or several keys.
* @param array $array the array to be sorted. The array will be modified after calling this method.
* @param string|\Closure|array $key the key(s) to be sorted by. This refers to a key name of the sub-array
...
...
framework/yii/helpers/BaseHtml.php
View file @
96e794b4
...
...
@@ -551,8 +551,11 @@ class BaseHtml
* in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks.
* When this option is specified, the radio button will be enclosed by a label tag.
* - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified.
* - container: array|boolean, the HTML attributes for the container tag. This is only used when the "label" option is specified.
* If it is false, no container will be rendered. If it is an array or not, a "div" container will be rendered
* around the the radio button.
*
* The rest of the options will be rendered as the attributes of the resulting tag. The values will
* The rest of the options will be rendered as the attributes of the resulting
radio button
tag. The values will
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
*
* @return string the generated radio button tag
...
...
@@ -571,9 +574,14 @@ class BaseHtml
if
(
isset
(
$options
[
'label'
]))
{
$label
=
$options
[
'label'
];
$labelOptions
=
isset
(
$options
[
'labelOptions'
])
?
$options
[
'labelOptions'
]
:
[];
unset
(
$options
[
'label'
],
$options
[
'labelOptions'
]);
$container
=
isset
(
$options
[
'container'
])
?
$options
[
'container'
]
:
[
'class'
=>
'radio'
];
unset
(
$options
[
'label'
],
$options
[
'labelOptions'
],
$options
[
'container'
]);
$content
=
static
::
label
(
static
::
input
(
'radio'
,
$name
,
$value
,
$options
)
.
' '
.
$label
,
null
,
$labelOptions
);
return
$hidden
.
static
::
tag
(
'div'
,
$content
,
[
'class'
=>
'radio'
]);
if
(
is_array
(
$container
))
{
return
$hidden
.
static
::
tag
(
'div'
,
$content
,
$container
);
}
else
{
return
$hidden
.
$content
;
}
}
else
{
return
$hidden
.
static
::
input
(
'radio'
,
$name
,
$value
,
$options
);
}
...
...
@@ -592,8 +600,11 @@ class BaseHtml
* in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks.
* When this option is specified, the checkbox will be enclosed by a label tag.
* - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified.
* - container: array|boolean, the HTML attributes for the container tag. This is only used when the "label" option is specified.
* If it is false, no container will be rendered. If it is an array or not, a "div" container will be rendered
* around the the radio button.
*
* The rest of the options will be rendered as the attributes of the resulting tag. The values will
* The rest of the options will be rendered as the attributes of the resulting
checkbox
tag. The values will
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
*
* @return string the generated checkbox tag
...
...
@@ -612,9 +623,14 @@ class BaseHtml
if
(
isset
(
$options
[
'label'
]))
{
$label
=
$options
[
'label'
];
$labelOptions
=
isset
(
$options
[
'labelOptions'
])
?
$options
[
'labelOptions'
]
:
[];
unset
(
$options
[
'label'
],
$options
[
'labelOptions'
]);
$container
=
isset
(
$options
[
'container'
])
?
$options
[
'container'
]
:
[
'class'
=>
'checkbox'
];
unset
(
$options
[
'label'
],
$options
[
'labelOptions'
],
$options
[
'container'
]);
$content
=
static
::
label
(
static
::
input
(
'checkbox'
,
$name
,
$value
,
$options
)
.
' '
.
$label
,
null
,
$labelOptions
);
return
$hidden
.
static
::
tag
(
'div'
,
$content
,
[
'class'
=>
'checkbox'
]);
if
(
is_array
(
$container
))
{
return
$hidden
.
static
::
tag
(
'div'
,
$content
,
$container
);
}
else
{
return
$hidden
.
$content
;
}
}
else
{
return
$hidden
.
static
::
input
(
'checkbox'
,
$name
,
$value
,
$options
);
}
...
...
tests/unit/data/
sphinx/ar
/ActiveRecord.php
→
tests/unit/data/
ar/sphinx
/ActiveRecord.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
/**
* Test Sphinx ActiveRecord class
...
...
tests/unit/data/
sphinx/ar
/ArticleDb.php
→
tests/unit/data/
ar/sphinx
/ArticleDb.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
use
yii\sphinx\ActiveRelation
;
use
yiiunit\data\ar\ActiveRecord
as
ActiveRecordDb
;
...
...
tests/unit/data/
sphinx/ar
/ArticleIndex.php
→
tests/unit/data/
ar/sphinx
/ArticleIndex.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
use
yii\db\ActiveRelation
;
...
...
tests/unit/data/
sphinx/ar
/ItemDb.php
→
tests/unit/data/
ar/sphinx
/ItemDb.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
use
yiiunit\data\ar\ActiveRecord
as
ActiveRecordDb
;
...
...
tests/unit/data/
sphinx/ar
/ItemIndex.php
→
tests/unit/data/
ar/sphinx
/ItemIndex.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
class
ItemIndex
extends
ActiveRecord
{
...
...
tests/unit/data/
sphinx/ar
/RuntimeIndex.php
→
tests/unit/data/
ar/sphinx
/RuntimeIndex.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
class
RuntimeIndex
extends
ActiveRecord
{
...
...
tests/unit/data/
sphinx/ar
/TagDb.php
→
tests/unit/data/
ar/sphinx
/TagDb.php
View file @
96e794b4
<?php
namespace
yiiunit\data\
sphinx\ar
;
namespace
yiiunit\data\
ar\sphinx
;
use
yiiunit\data\ar\ActiveRecord
as
ActiveRecordDb
;
...
...
tests/unit/extensions/sphinx/ActiveDataProviderTest.php
View file @
96e794b4
...
...
@@ -4,8 +4,8 @@ namespace yiiunit\extensions\sphinx;
use
yii\data\ActiveDataProvider
;
use
yii\sphinx\Query
;
use
yiiunit\data\
sphinx\ar
\ActiveRecord
;
use
yiiunit\data\
sphinx\ar
\ArticleIndex
;
use
yiiunit\data\
ar\sphinx
\ActiveRecord
;
use
yiiunit\data\
ar\sphinx
\ArticleIndex
;
/**
* @group sphinx
...
...
tests/unit/extensions/sphinx/ActiveRecordTest.php
View file @
96e794b4
...
...
@@ -3,9 +3,9 @@
namespace
yiiunit\extensions\sphinx
;
use
yii\sphinx\ActiveQuery
;
use
yiiunit\data\
sphinx\ar
\ActiveRecord
;
use
yiiunit\data\
sphinx\ar
\ArticleIndex
;
use
yiiunit\data\
sphinx\ar
\RuntimeIndex
;
use
yiiunit\data\
ar\sphinx
\ActiveRecord
;
use
yiiunit\data\
ar\sphinx
\ArticleIndex
;
use
yiiunit\data\
ar\sphinx
\RuntimeIndex
;
/**
* @group sphinx
...
...
@@ -41,10 +41,9 @@ class ActiveRecordTest extends SphinxTestCase
$this
->
assertTrue
(
$articles
[
1
]
instanceof
ArticleIndex
);
// find fulltext
$articles
=
ArticleIndex
::
find
(
'cats'
);
$this
->
assertEquals
(
1
,
count
(
$articles
));
$this
->
assertTrue
(
$articles
[
0
]
instanceof
ArticleIndex
);
$this
->
assertEquals
(
1
,
$articles
[
0
]
->
id
);
$article
=
ArticleIndex
::
find
(
2
);
$this
->
assertTrue
(
$article
instanceof
ArticleIndex
);
$this
->
assertEquals
(
2
,
$article
->
id
);
// find by column values
$article
=
ArticleIndex
::
find
([
'id'
=>
2
,
'author_id'
=>
2
]);
...
...
@@ -168,7 +167,7 @@ class ActiveRecordTest extends SphinxTestCase
$record
=
RuntimeIndex
::
find
([
'id'
=>
2
]);
$record
->
content
=
'Test content with '
.
$query
;
$record
->
save
();
$rows
=
RuntimeIndex
::
find
(
$query
);
$rows
=
RuntimeIndex
::
find
(
)
->
match
(
$query
);
$this
->
assertNotEmpty
(
$rows
);
// updateAll
...
...
tests/unit/extensions/sphinx/ActiveRelationTest.php
View file @
96e794b4
...
...
@@ -2,10 +2,10 @@
namespace
yiiunit\extensions\sphinx
;
use
yiiunit\data\
sphinx\ar
\ActiveRecord
;
use
yiiunit\data\
ar\sphinx
\ActiveRecord
;
use
yiiunit\data\ar\ActiveRecord
as
ActiveRecordDb
;
use
yiiunit\data\
sphinx\ar
\ArticleIndex
;
use
yiiunit\data\
sphinx\ar
\ArticleDb
;
use
yiiunit\data\
ar\sphinx
\ArticleIndex
;
use
yiiunit\data\
ar\sphinx
\ArticleDb
;
/**
* @group sphinx
...
...
tests/unit/extensions/sphinx/ExternalActiveRelationTest.php
View file @
96e794b4
...
...
@@ -2,11 +2,11 @@
namespace
yiiunit\extensions\sphinx
;
use
yiiunit\data\
sphinx\ar
\ActiveRecord
;
use
yiiunit\data\
ar\sphinx
\ActiveRecord
;
use
yiiunit\data\ar\ActiveRecord
as
ActiveRecordDb
;
use
yiiunit\data\
sphinx\ar
\ArticleIndex
;
use
yiiunit\data\
sphinx\ar
\ArticleDb
;
use
yiiunit\data\
sphinx\ar
\TagDb
;
use
yiiunit\data\
ar\sphinx
\ArticleIndex
;
use
yiiunit\data\
ar\sphinx
\ArticleDb
;
use
yiiunit\data\
ar\sphinx
\TagDb
;
/**
* @group sphinx
...
...
tests/unit/framework/helpers/ArrayHelperTest.php
View file @
96e794b4
...
...
@@ -303,4 +303,21 @@ class ArrayHelperTest extends TestCase
],
],
$result
);
}
public
function
testKeyExists
()
{
$array
=
[
'a'
=>
1
,
'B'
=>
2
,
];
$this
->
assertTrue
(
ArrayHelper
::
keyExists
(
'a'
,
$array
));
$this
->
assertFalse
(
ArrayHelper
::
keyExists
(
'b'
,
$array
));
$this
->
assertTrue
(
ArrayHelper
::
keyExists
(
'B'
,
$array
));
$this
->
assertFalse
(
ArrayHelper
::
keyExists
(
'c'
,
$array
));
$this
->
assertTrue
(
ArrayHelper
::
keyExists
(
'a'
,
$array
,
false
));
$this
->
assertTrue
(
ArrayHelper
::
keyExists
(
'b'
,
$array
,
false
));
$this
->
assertTrue
(
ArrayHelper
::
keyExists
(
'B'
,
$array
,
false
));
$this
->
assertFalse
(
ArrayHelper
::
keyExists
(
'c'
,
$array
,
false
));
}
}
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